2

I want to convert this array

[['a', 'b'],['c', 'd'],['e', 'f']] 

to this hash

{
  "a" : "c",
  "b" : "d"
},
{
  "a" : "e",
  "b" : "f"
}

How to do it?

I tried to use group_by and normal iterators but no luck so far. Any ideas?

Pramod Shinde
  • 1,802
  • 1
  • 15
  • 28
Ahmad hamza
  • 1,816
  • 1
  • 23
  • 46

5 Answers5

7
▶ arr = [[:a, :b],[:c, :d],[:e, :f],[:g, :h]]
▶ key, values = arr.first, arr[1..-1]
▶ values.map { |v| key.zip v }.map &:to_h
#⇒ [
#  [0] {
#    :a => :c,
#    :b => :d
#  },
#  [1] {
#    :a => :e,
#    :b => :f
#  },
#  [2] {
#    :a => :g,
#    :b => :h
#  }
# ]

Please note that unlike other solutions presented here at the moment this one will map first element as keys to a tail of arbitrary length.

UPD For legacy rubies, not having Array#to_h:

values.map { |v| key.zip v }.map { |e| Hash[e] }
Aleksei Matiushkin
  • 119,336
  • 10
  • 100
  • 160
  • i was just trying it.. Thanks for the answer. – Ahmad hamza Apr 23 '15 at 10:47
  • A twist in the question, suppose if i have the set of 5 elements in an array instead of two and i want to ignore the first element of each array.? – Ahmad hamza Apr 23 '15 at 10:55
  • Also can you please explain why you have taken the arr array from 1 to -1.? and why not [1..2] ? – Ahmad hamza Apr 23 '15 at 11:01
  • 1
    @ahmadhamza This solution permits you to have as many elements in the hash as you want. To drop first one you’ll need to map result to `unshift` a first element. `[1..-1]` is there because the original array may be of any length. – Aleksei Matiushkin Apr 23 '15 at 11:06
2

I would use Array#product:

arr = [[:a, :b], [:c, :d], [:e, :f]]

arr.first.product(arr[1..-1]).map(&:to_h)
  #=> [{:a=>:c, :b=>:d}, {:a=>:e, :b=>:f}]

If arr can be modified, we can write:

arr.shift.product(arr).map(&:to_h)
Cary Swoveland
  • 106,649
  • 6
  • 63
  • 100
1
x = [["a", "b"],["c", "d"],["e", "f"]]
x[1..-1].map { |vs| {x[0][0] => vs[0], x[0][1] => vs[1]} }

Something like this.

iced
  • 1,562
  • 8
  • 10
1
a= [['a', 'b'],['c', 'd'],['e', 'f']]

a[1..-1].inject([]) { |sum, s| sum << {a[0][0] => s[0], a[0][1] => s[1]} }

=> [{"a"=>"c", "b"=>"d"}, {"a"=>"e", "b"=>"f"}]

improved:

a= [['a', 'b', 'c'],['d', 'e', 'f'],['g', 'h', 'k']]
a[1..-1].inject([]) do |sum, s|
    hash = {}
    a[0].each_with_index { |it, i| hash.merge!({it => s[i]}) }
    sum << hash
end
=> [{"a"=>"d", "b"=>"e", "c"=>"f"}, {"a"=>"g", "b"=>"h", "c"=>"k"}]

This way is more flexible.

pangpang
  • 8,581
  • 11
  • 60
  • 96
1

I would write:

key = a.shift
p a.map{|x| key.zip(x).to_h } => [{"a"=>"c", "b"=>"d"}, {"a"=>"e", "b"=>"f"}]
hirolau
  • 13,451
  • 8
  • 35
  • 47