Search code examples
rubysplat

Unexpected result with splat operator


I have a hash, whose values are an array of size 1:

hash = {:start => [1]}

I want to unpack the arrays as in:

hash.each_pair{ |key, value| hash[key] = value[0] } # => {:start=>1}

and I thought the *-operator as in the following would work, but it does not give the expected result:

hash.each_pair{ |key, value| hash[key] = *value } # => {:start=>[1]}

Why does *value return [1] and not 1?


Solution

  • Because the []= method applied to hash takes only one argument in addition to the key (which is put inside the [] part), and a splatted/expanded array, which is in general a sequence of values (which coincidentally happens to be a single element in this particular case) cannot be directly accepted as the argument as is splatted. So it is accepted by the argument of []= as an array after all.

    In other words, an argument (of the []= method) must be an object, but splatted elements (such as :foo, :bar, :baz) are not an object. The only way to interpret them as an object is to put them back into an array (such as [:foo, :bar, :baz]).

    Using the splat operator, you can do it like this:

    hash.each_pair{|key, value| hash.[]= key, *value}