Search code examples
crystal-lang

Crystal: how to increase the number of types an array can hold after instantiation


I'm building a table of data. At first, the rows of this table are most easily filled by key / value so I use a hash

a = Hash(Int32, Symbol).new
a[1] = :one

Once that's done, it's more convenient to work with an array (I need to sort the data for example). Easy enough:

a.to_a # => [{1, :one}]

But now I'm discovering that for my formatter to work properly (multi-page table, using latex) things just make more sense if I can store another data type in that array, for example, a string. But it's too late! The type of the array is fixed; it won't admit a string.

a << "str" # => ERROR!

The solution I've come up with so far doesn't seem very elegant:

a = Hash(Int32, Symbol).new
a[1] = :one
arr = Array(String | Tuple(Int32, Symbol)).new
a.each do |k,v|
  arr << {k,v}
end
arr << "str" # no problem now

Is there a more "Crystal" / elegant way?


Solution

  • Just use to_a with as it can be used to cast to a "bigger" type as the docs call it

    a = Hash(Int32, Symbol).new
    a[1] = :one
    arr = a.to_a.map { |x| x.as(String | Tuple(Int32, Symbol)) }
    arr << "str" # [{1, :one}, "str"]