Convert this Array:
a = ["item 1", "item 2", "item 3", "item 4"]
...to a Hash:
{ "item 1" => "item 2", "item 3" => "item 4" }
i.e. elements at even indexes are keys and odd ones are values.
Convert this Array:
a = ["item 1", "item 2", "item 3", "item 4"]
...to a Hash:
{ "item 1" => "item 2", "item 3" => "item 4" }
i.e. elements at even indexes are keys and odd ones are values.
a = ["item 1", "item 2", "item 3", "item 4"]
h = Hash[*a] # => { "item 1" => "item 2", "item 3" => "item 4" }
That's it. The * is called the splat operator.
One caveat per @Mike Lewis (in the comments): "Be very careful with this. Ruby expands splats on the stack. If you do this with a large dataset, expect to blow out your stack."
So, for most general use cases this method is great, but use a different method if you want to do the conversion on lots of data. For example, @Łukasz Niemier (also in the comments) offers this method for large data sets:
h = Hash[a.each_slice(2).to_a]
* is called the splat operator. It takes an array and converts it a literal list of items. So *[1,2,3,4] => 1, 2, 3, 4. In this example, the above is equivalent to doing Hash["item 1", "item 2", "item 3", "item 4"]. And Hash has a [] method that accepts a list of arguments (making even indexes keys and odd indexes values), but Hash[] does not accept an array, so we splat the array using *.Hash[a.each_slice(2).to_a].a.each_slice(2).to_h (at least in YARV).Ruby 2.1.0 introduced a to_h method on Array that does what you require if your original array consists of arrays of key-value pairs: http://www.ruby-doc.org/core-2.1.0/Array.html#method-i-to_h.
[[:foo, :bar], [1, 2]].to_h
# => {:foo => :bar, 1 => 2}
bar needs to be a symbol, and the symbol :2 should be an integer. So, your expression corrected is a = [[:foo, 1], [:bar, 2]]).Just use Hash.[] with the values in the array. For example:
arr = [1,2,3,4]
Hash[*arr] #=> gives {1 => 2, 3 => 4}
*arr converts arr into an argument list, so this is calling the [] method of Hash with the contents of arr as arguments.Or if you have an array of [key, value] arrays, you can do:
[[1, 2], [3, 4]].inject({}) do |r, s|
r.merge!({s[0] => s[1]})
end # => { 1 => 2, 3 => 4 }
{ [1, 2] => [3, 4] }. And since the question's title says "Array to Hash" and the built-in "Hash to Array" method does: { 1 => 2, 3 => 4}.to_a # => [[1, 2], [3, 4]], I thought more than one could end here trying to get the inverse of the built-in "Hash to Array" method. Actually, that's how I ended here anyway.Hash[arr] will do the job for you.#inject method. With #merge!, #each_with_object should have been used. If #inject is insisted upon, #merge rather than #merge! should have been used.[[1, 2], [3, 4]].to_hThis is what I was looking for when googling this:
[{a: 1}, {b: 2}].reduce({}) { |h, v| h.merge v }
=> {:a=>1, :b=>2}
.reduce(&:merge!)[{a: 1}, {b: 2}].reduce(&:merge!) evaluates to {:a=>1, :b=>2}[{a: 1}, {b: 2}].reduce(&:merge!) is the same as [{a: 1}, {b: 2}].reduce { |m, x| m.merge(x) } which is the same as [{b: 2}].reduce({a: 1}) { |m, x| m.merge(x) }.{}, or use non-mutating merge which has the same performance issue as described above; (2) the input array needs to have at least 1 element, otherwise you will get nil back instead of an empty hashEnumerator includes Enumerable. Since 2.1, Enumerable also has a method #to_h. That's why, we can write :-
a = ["item 1", "item 2", "item 3", "item 4"]
a.each_slice(2).to_h
# => {"item 1"=>"item 2", "item 3"=>"item 4"}
Because #each_slice without block gives us Enumerator, and as per the above explanation, we can call the #to_h method on the Enumerator object.
You could try like this, for single array
irb(main):019:0> a = ["item 1", "item 2", "item 3", "item 4"]
=> ["item 1", "item 2", "item 3", "item 4"]
irb(main):020:0> Hash[*a]
=> {"item 1"=>"item 2", "item 3"=>"item 4"}
for array of array
irb(main):022:0> a = [[1, 2], [3, 4]]
=> [[1, 2], [3, 4]]
irb(main):023:0> Hash[*a.flatten]
=> {1=>2, 3=>4}
a = ["item 1", "item 2", "item 3", "item 4"]
Hash[ a.each_slice( 2 ).map { |e| e } ]
or, if you hate Hash[ ... ]:
a.each_slice( 2 ).each_with_object Hash.new do |(k, v), h| h[k] = v end
or, if you are a lazy fan of broken functional programming:
h = a.lazy.each_slice( 2 ).tap { |a|
break Hash.new { |h, k| h[k] = a.find { |e, _| e == k }[1] }
}
#=> {}
h["item 1"] #=> "item 2"
h["item 3"] #=> "item 4"
Hash[ ... ] but want to use it as a chained method (like you can do with to_h) you can combine Boris suggestions and write: arr.each_slice( 2 ).map { |e| e }.tap { |a| break Hash[a] }All answers assume the starting array is unique. OP did not specify how to handle arrays with duplicate entries, which result in duplicate keys.
Let's look at:
a = ["item 1", "item 2", "item 3", "item 4", "item 1", "item 5"]
You will lose the item 1 => item 2 pair as it is overridden bij item 1 => item 5:
Hash[*a]
=> {"item 1"=>"item 5", "item 3"=>"item 4"}
All of the methods, including the reduce(&:merge!) result in the same removal.
It could be that this is exactly what you expect, though. But in other cases, you probably want to get a result with an Array for value instead:
{"item 1"=>["item 2", "item 5"], "item 3"=>["item 4"]}
The naïve way would be to create a helper variable, a hash that has a default value, and then fill that in a loop:
result = Hash.new {|hash, k| hash[k] = [] } # Hash.new with block defines unique defaults.
a.each_slice(2) {|k,v| result[k] << v }
a
=> {"item 1"=>["item 2", "item 5"], "item 3"=>["item 4"]}
It might be possible to use assoc and reduce to do above in one line, but that becomes much harder to reason about and read.
each_with_object({}) (ruby >= 1.9.1.378) as in this related answer.