0

Assume arr is an array [[1,3],[2,5],[3,8]]. I was wondering what * means. What does it mean?

hash = Hash[*arr.flatten] # => {1=>3, 2=>5, 3=>8}

I tried the following

arr.flatten # => [1, 3, 2, 5, 3, 8]
Hash[arr.flatten] # => {}
Hash[*a.flatten] # => {1=>3, 2=>5, 3=>8}
sawa
  • 165,429
  • 45
  • 277
  • 381
AirWick219
  • 894
  • 8
  • 27
  • If you have trouble remembering what "splat" does, visualize a teenage boy eying a mustard packet on the floor at McDonald's. – Cary Swoveland Jun 20 '14 at 18:03

2 Answers2

1

Here is the explanation

When you do array.flatten it will give you one flatten array where all inner array slatted. Now You are putting this flatten array inside the Hash::[] method. But Hash::[] supports the below constructs :

Hash[ key, value, ... ] → new_hash 
# or
Hash[ [ [key, value], ... ] ] → new_hash

Now array.flatten gives you [1, 3, 2, 5, 3, 8]. Now you are putting this array inside Hash[] like Hash[[1, 3, 2, 5, 3, 8]]. Now compare with the above 2 structures. Does either of them match ? NO. So you need to splat the inner array again, thus it need (splatted operator)* to splat the inner array.

Now you did Hash[*[1, 3, 2, 5, 3, 8]], which gives Hash[1, 3, 2, 5, 3, 8]. Now again check from the above 2 constructs. Does it match with either of the 2 ? This time YES, first one. So you got the desired hash {1=>3, 2=>5, 3=>8}.

BTW, you don't need to splat, as the second construt exactly matched when you put array inside Hash::[] directly.

array = [[1,3],[2,5],[3,8]]
Hash[array] # => {1=>3, 2=>5, 3=>8}

The above worked, because Hash[array] means Hash[[[1,3],[2,5],[3,8]]], which exactly the second structure as documentation suggested.

Read some examples to see how splatting work in Ruby.

There is another construct :-

 Hash[ object ] → new_hash

This I think is also important to tell you why you got {}. Hash[[1, 3, 2, 5, 3, 8]] same as the last type of construct as per the doc. The doc is saying -

The second and third form take a single argument which is either an array of key-value pairs or an object convertible to a hash.

So. [1,3,2,5,3,8] it is an Array object not convertible to Hash. Currently it is giving you an empty hash, if an object as per the third construct. But it will throw error in future version of release. See Below warnings.

[1] pry(main)> Hash[[1,2]]
(pry):1: warning: wrong element type Fixnum at 0 (expected array)
(pry):1: warning: ignoring wrong elements is deprecated, remove them explicitly
(pry):1: warning: this causes ArgumentError in the next release
(pry):1: warning: wrong element type Fixnum at 1 (expected array)
(pry):1: warning: ignoring wrong elements is deprecated, remove them explicitly
(pry):1: warning: this causes ArgumentError in the next release
=> {}

My Ruby version is :

ruby 2.0.0p451 (2014-02-24 revision 45167) [i686-linux]
Community
  • 1
  • 1
Arup Rakshit
  • 116,827
  • 30
  • 260
  • 317
  • a little confusing .. so with ur logic are you saying Hash[*[array.faltten]] == Hash[*array.faltten] ? – AirWick219 Jun 20 '14 at 17:14
  • Just to be clear, `splat` means `*`, and more can be read about what it does here http://endofline.wordpress.com/2011/01/21/the-strange-ruby-splat/ – lightswitch05 Jun 20 '14 at 17:26
0

When you pass an argument to the Hash class you can put it in parentheses...

Hash(arr.flatten)

or without...

Hash arr.flatten

In either case, Hash takes the argument and if it's an array with an even number of elements, it will create a hash where the odd elements are the keys and the even elements are the values.

Hash can also take square brackets to preform a similar operation

Hash[1, 2]
=> {1=>2}

BUT, when you do this...

Hash[arr.flatten]

You are passing the array WITHIN the array so you're getting unexpected results.

When you do this...

Hash[*arr.flatten] 

You are saying take the array arr.flatten and pass it, not as an array, but as individual separate arguments to the method.

So where Hash[arr.flatten] is actually Hash[[1, 3, 2, 5, 3, 8]] (an array containing one element which is an array) instead Hash[*arr.flatten] is actually Hash[1, 3, 2, 5, 3, 8](an array containing six elements)

Interestingly enough, the [] method can take an array containing arrays of key, value pairs so..

Hash[arr]

Works fine! You don't have to flatten or splat anything.

SteveTurczyn
  • 36,057
  • 6
  • 41
  • 53