Crystal: Reducing Array to Hash requires more types than necessary

Created on 3 Apr 2017  Â·  6Comments  Â·  Source: crystal-lang/crystal

I'm just getting the hang of using hashes with Crystal… I've managed to reduce an Array down to Hash but the types required on Hash are more than there should be. For example I have an array of pairs of Int32, Symbol so I should be able to create a hash of Int32 => Symbol. But in the reduce process it errors of not finding a type matching Int32 | Symbol => Int32 | Symbol.

Here's what I believe should work:

index = 0
columns = [:a, :b, :c, :d]
a = columns.
  map { |x| [index.tap{index+=1}, x] }.
  reduce({} of Int32 => Symbol) {|arr,(k,v)| arr[k]=v; arr}
puts a

And the failing results: https://play.crystal-lang.org/#/r/1swh

But once I drop in both types it works:

index = 0
columns = [:a, :b, :c, :d]
a = columns.
  map { |x| [index.tap{index+=1}, x] }.
  reduce({} of Int32 | Symbol => Int32 | Symbol) {|arr,(k,v)| arr[k]=v; arr}
puts a

Output: {0 => :a, 1 => :b, 2 => :c, 3 => :d}

So that's what seems wrong to me.


_If you could be so kind as to help me write a better Array to Hash reduction I would greatly appreciate it. Right now I'm thinking of using select to create a union of all the types for the keys and likewise the values before defining a Hash to reduce it to. Am I going about it the right way?_

_I've read the Hash documentation and I feel there's so much more that could be written there to help clarify use scenarios._

question

All 6 comments

[index.tap{index+=1}, x] 

Use braces instead:

{index.tap{index+=1}, x}

By creating an array, the resulting type is Array(Int32 | Symbol), since arrays are homogenous (e.g. every element must be of the same type).

Tuples, created with {a, b, c}, have compile-time-fixed lengths and are heterogeneous, so it's perfectly fine to have Tuple(Int32, Symbol).

Wow! That works! Thanks for the tip!

Also:

index = 0
columns = [:a, :b, :c, :d]
a = columns
  .map_with_index { |x, i| {i, x} } # change here
  .to_h # but here  too :-)
puts a

Thanks you @asterite ! That's very elegant.

@bcardiff I take it that by you closing this that it's not considered an issue that reducing nested arrays behaves this way?

Array of Array wont be reduceable to Hash. But Array of Tuples yes as shown by asterite. I closed because i understood you were satisfied with the result.

Array(T) will return a T always, for all indices.
Tuples on the other side can track the different types per index, so the code is able to propagate types accordingly without creating unions.

Feel free to ask if there something unclear!

Was this page helpful?
0 / 5 - 0 ratings

Related issues

HCLarsen picture HCLarsen  Â·  162Comments

sergey-kucher picture sergey-kucher  Â·  66Comments

farleyknight picture farleyknight  Â·  64Comments

RX14 picture RX14  Â·  62Comments

straight-shoota picture straight-shoota  Â·  91Comments