Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Ruby: wrong element type Symbol at 0 (expected array)

Tags:

arrays

ruby

I am wondering why trying to convert this array to a hash causes an error:

[:a, [1,2,3]].to_h
=> TypeError: wrong element type Symbol at 0 (expected array)
Hash[ [:a, [1,2,3]] ]
=> ArgumentError: invalid number of elements (3 for 1..2)

The array hash two items. So it should be easily converted to a key/value pair, which is what a hash is.

I have a collection that looks like this:

 [ [:a, [1,2,3]], [:b, [4,5,6]] ]

And I just want to make it an array of hashes:

[ [:a, [1,2,3]], [:b, [4,5,6]] ].collect {|collection| Hash[collection] }
=> ArgumentError: invalid number of elements (3 for 1..2)

Why cannot it not convert an array of two items into a key/value pair?

I could do something like this:

arr.collect {|item| { item[0] => item[1] } }
=> [{:a=>[1, 2, 3]}, {:b=>[4, 5, 6]}] 
like image 922
Daniel Viglione Avatar asked Apr 29 '18 20:04

Daniel Viglione


2 Answers

Wrap it in [] once more

You need an array of pairs, since one Hash can contain many of those, and that feature is reflected in what its constructors accept. A single pair is an array with 2 elements.

Hash[ [:a, [1,2,3]] ]

This is a call to Hash.[] with a single pair [:a, [1,2,3]].
To make it an array of pairs, wrap once more, getting [[:a, [1,2,3]]] or

Hash[[[:a, [1,2,3]]]
#   ↑↑↑
#   ||\_pair
#   |\_array of pairs
#   \_call to Hash.[]

The amount of square brackets here is nauseating.

If your end goal is an array of hashes, each being a single pair, you could use destructuring in block arguments like so:

[ [:a, [1,2,3]], [:b, [4,5,6]] ].collect {|(a, b)| {a => b} }

This is literally the same thing you're suggesting at the end of your question, only without [].

like image 69
D-side Avatar answered Oct 20 '22 06:10

D-side


This should work

.to_h takes an array of multple key value pairs

[ [:a, [1,2,3]], [:b, [4,5,6]] ].to_h
=> {:a=>[1, 2, 3], :b=>[4, 5, 6]}

[ [:a, [1,2,3]] ].to_h
=> {:a=>[1, 2, 3]}

Hash[] takes a single key and value

Hash[:a, [1,2,3]]
=> {:a=>[1, 2, 3]}

While these won't

.to_h expects each element in the array to be an array with 2 items. Hence if any item in the array is a not an array itself, it gives a type error.

[:a, [1,2,3]].to_h
TypeError: wrong element type Symbol at 0 (expected array)

Hash[] with a two arrays returns a hash with the first array as the key and the second array as the value, as it's expecting a single key and value.

Hash[ [:a, [1,2,3]], [:b, [4,5,6]] ]
=> {[:a, [1, 2, 3]]=>[:b, [4, 5, 6]]}
like image 26
Arye Eidelman Avatar answered Oct 20 '22 06:10

Arye Eidelman