0

Can anyone explain me how an array is converted into a Hash here?

puts Hash[*[[:first_name, 'Shane'], [:last_name, 'Harvie']].flatten]

I am not understanding what happens behind when we call Hash[*[]]].flatten].

5 Answers 5

2

You just need to do :

Hash[[[:first_name, 'Shane'], [:last_name, 'Harvie']]]
# => {:first_name=>"Shane", :last_name=>"Harvie"}

Look at the documentation syntax :

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

If you do use faltten then below is the result :-

[[[:first_name, 'Shane'], [:last_name, 'Harvie']].flatten]
# => [[:first_name, "Shane", :last_name, "Harvie"]]

If you do use splat with faltten then you would get below :

[*[[:first_name, 'Shane'], [:last_name, 'Harvie']].flatten]
# => [:first_name, "Shane", :last_name, "Harvie"]

Now, Hash[*[[:first_name, 'Shane'], [:last_name, 'Harvie']].flatten] will give you the hash, as my top code gives. but you don't need to do this much work, as Hash documentation clearly matches with your input data, so only Hash[input_data] is enough.

Sign up to request clarification or add additional context in comments.

2 Comments

What does * indicate there?
@Shane this is splat operator
2

Hash class defines a method []. This methods takes any number of arguments, takes each pair and creates a new hash with first element of each pair being keys and the second element being a value. If you pass odd amount ov arguments, this will fail. Also it allows you to pass 2d array or any number of 2 element arrays.

Now you have 2d array: [[:first_name, 'Shane'], [:last_name, 'Harvie']]. When you call flatten, you merge all the inner arrays in one:

Hash[[[:first_name, 'Shane'], [:last_name, 'Harvie']].flatten]
Hash[[:first_name, 'Shane', :last_name, 'Harvie']]

Now if you use splat operator, you extract all the elements and pass them to [] method as separate arguments, so this transaltes to:

Hash[*[[:first_name, 'Shane'], [:last_name, 'Harvie']].flatten]
Hash[:first_name, 'Shane', :last_name, 'Harvie']

Note however that it is not needed - Hash[] can deal with the initial form. Just do:

Hash[[[:first_name, 'Shane'], [:last_name, 'Harvie']]]

Comments

1

First the array is flattened:

[[:first_name, 'Shane'], [:last_name, 'Harvie']].flatten
# becomes: [:first_name, 'Shane', :last_name, 'Harvie']

Since the Hash#[] method accepts an arbitrary number of parameters like so

Hash['a', 'b', 'c', 'd']

and not an array you need to use the splat operator (*) to expand the array on the stack so the values get used as parameters

Hash[*[:first_name, 'Shane', :last_name, 'Harvie']]
# becomes: Hash[:first_name, 'Shane', :last_name, 'Harvie']

And Arup is right, you don't need the flatten, because the Hash#[] method accepts 2d arrays as well.

Comments

1

What we get without using of splat * :--

[[[:first_name, 'Shane'], [:last_name, 'Harvie']].flatten]
#=> [[:first_name, "Shane", :last_name, "Harvie"]]

So here you get a 2D array and '' => "".

Now, let's see what we get with splat * being used:--

[*[[:first_name, 'Shane'], [:last_name, 'Harvie']].flatten]
#=> [:first_name, "Shane", :last_name, "Harvie"]

Here you get 1D array, so splat has caused the inner array to come out of its container array.

So Hash[*[[:first_name, 'Shane'], [:last_name, 'Harvie']].flatten] is same to Hash[:first_name, "Shane", :last_name, "Harvie"]

#=> {:first_name=>"Shane", :last_name=>"Harvie"}

Comments

1
Hash[*[[:first_name, 'Shane'], [:last_name, 'Harvie']].flatten]

The best thing we can do is to start from the inside and then go outwards.

In the innermost part you have two arrays that have two elements each: A symbol and a string.

Going for the next set of brackets, we have an array that contain those two arrays.

flatten will flatten the two arrays inside, so that we have one array containg for elements, instead of an array containing another two arrays.

The star(*) operator, expands an array into a list of arguments to be used in a function.

So

[:first_name, 'Shane', :last_name, 'Harvie']

will turn into

:first_name, 'Shane', :last_name, 'Harvie'

the last part is Hash[]

which is a function that takes an array of parameters and turns them into a Hash.

{:first_name=>'Shane', :last_name=>'Harvie'}

Voila. It's simpler than it looked at first.

Observations:

If you take a look at the documentation of Hash, you'll see that you could have just passed multiple arrays to Hash[] and it would take care of it.

References:

5 Comments

-1. You wrote as if * turns [:first_name, 'Shane', :last_name, 'Harvie'] into [:first_name=>'Shane', :last_name=>'Harvie'], but the notation [:first_name=>'Shane', :last_name=>'Harvie'] represents a hash enclosed in an array, which means that * by itself did the array to hash conversion. This is clearly wrong.
Also your A symbol and a literal (string), is inconsistent. They are a symbol and a string, both a literal.
sawa: Will fix the notation cause that was not what I meant. and the symbol/literal thing too.
sawa: Done. Got it fixed. Thanks for mentioning it.
Sorry for that. Fixed :)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.