tags:

views:

1824

answers:

6

In Ruby, given an array in one of the following forms...

[apple, 1, banana, 2]
[[apple, 1], [banana, 2]]

...what is the best way to convert this into a hash in the form of...

{apple => 1, banana => 2}
+2  A: 

This but here is one way of converting an Array to a Hash:

 require "enumerator"

 class Array
   def to_h
     Hash[*enum_with_index.to_a.flatten]
   end
 end

%w{a b c d}.to_h  # =>  {"a"=>0, "b"=>1, "c"=>2, "d"=>3}

Another sample:

["foo", "bar", "foo1", "bar1","foo2", "bar2"]   convert to
{"foo"=>"bar", "foo1"=>"bar1","foo2"=>"bar2"}

def array_to_hash(array)
  count = 0
  hash = Hash.new
  (array.length / 2).times do
    hash[array[count]] = array[count+1]
    count += 2
  end
  return hash
end
Espo
I was just needing this. Why it's hidden down at zero points in a pretty popular question is unknown... Anyway, the non-monkey patched version is just hash = Hash[*a.enum_with_index.to_a.flatten]
Yar
+19  A: 

Simply use Hash[*array_variable.flatten]

For example:

a1 = ['apple', 1, 'banana', 2]
h1 = Hash[*a1.flatten]
puts "h1: #{h1.inspect}"

a2 = [['apple', 1], ['banana', 2]]
h2 = Hash[*a2.flatten]
puts "h2: #{h2.inspect}"
John Topley
+1  A: 

Edit: Saw the responses posted while I was writing, Hash[a.flatten] seems the way to go. Must have missed that bit in the documentation when I was thinking through the response. Thought the solutions that I've written can be used as alternatives if required.

The second form is simpler:

a = [[:apple, 1], [:banana, 2]]
h = a.inject({}) { |r, i| r[i.first] = i.last; r }

a = array, h = hash, r = return-value hash (the one we accumulate in), i = item in the array

The neatest way that I can think of doing the first form is something like this:

a = [:apple, 1, :banana, 2]
h = {}
a.each_slice(2) { |i| h[i.first] = i.last }
Daemin
A: 

Not sure if it's the best way, but this works:

a = ["apple", 1, "banana", 2]
m1 = {}
for x in (a.length / 2).times:
  m1[a[x*2]] = a[x*2 + 1]
end

b = [["apple", 1], ["banana", 2]]
m2 = {}
for x,y in b:
  m2[x] = y
end
Anders Sandvig
A: 

If the numeric values are seq indexes, then we could have simpler ways... Here's my code submission, My Ruby is a bit rusty

   input = ["cat", 1, "dog", 2, "wombat", 3]
   hash = Hash.new
   input.each_with_index {|item, index|
     if (index%2 == 0) hash[item] = input[index+1]
   }
   hash   #=> {"cat"=>1, "wombat"=>3, "dog"=>2}
Gishu
A: 

Appending to the answer but using anonymous arrays and annotating: e.g.,

Hash[*("a,b,c,d".split(',').zip([1,2,3,4]).flatten)]

Taking that answer apart, starting from the inside:

"a,b,c,d" is actually a string split on commas into an array zip that together with the following array [1,2,3,4] is an actual array

The intermediate result is [[a,1],[b,2],[c,3],[d,4]]

flatten then transforms that to [a,1,b,2,c,3,d,4] and then [a,1,b,2,c,3,d,4] unrolls that into a,1,b,2,c,3,d,4 which we can use as the arguments to the Hash[] method; i.e., Hash[("a,b,c,d".split(',').zip([1,2,3,4]).flatten)] which yields {"a"=>1, "b"=>2, "c"=>3, "d"=>4}

StevenJenkins