1

http://codepad.org/WmYzQLiS

I'd like to merge these two arrays:

a = { :a => 'a', :b => 'b', :d => 'd' }
b = { :a => '1', :b => 'b', :c => 'c' }

Into a hash that looks like this:

{:a => ["a", "1"], :b => ["b", "b"], :c => [nil, "c"], :d => ["d", nil] }

This obviously doesn't work:

p a.merge(b) { |k, v1, v2| [v1, v2] }    # {:c=>"c", :a=>["a", "1"], :b=>["b", "b"], :d=>"d"}

2 Answers 2

2

It's because Hash#merge call the block only for the duplicate keys.


a = { :a => 'a', :b => 'b', :d => 'd' }
b = { :a => '1', :b => 'b', :c => 'c' }

Hash[(a.keys|b.keys).map { |key|
  [key, [a.fetch(key, nil), b.fetch(key, nil)]]
}]
# => {:a=>["a", "1"], :b=>["b", "b"], :d=>["d", nil], :c=>[nil, "c"]}

# In Ruby 2.1+
(a.keys|b.keys).map { |key|
  [key, [a.fetch(key, nil), b.fetch(key, nil)]]
}.to_h
Sign up to request clarification or add additional context in comments.

1 Comment

Awesome! Thanks for the fast answer!
2
(a.keys | b.keys).each_with_object({}) { |k,h| h[k] = [a[k], b[k]] }
  #=> {:a=>["a", "1"], :b=>["b", "b"], :d=>["d", nil], :c=>[nil, "c"]}

This is easy to generalize for an arbitrary number of hashes.

arr = [{ :a => 'a', :b => 'b',            :d => 'd' },
       { :a => '1', :b => 'b', :c => 'c'            },
       {            :b => '0', :c => 'b', :d => 'c' }]

arr.reduce([]) { |ar,h| ar | h.keys }
   .each_with_object({}) { |k,h| h[k] = arr.map { |g| g[k] } }
  #=> {:a=>["a", "1", nil], :b=>["b", "b", "0"],
  #    :d=>["d", nil, "c"], :c=>[nil, "c", "b"]}

1 Comment

#each_with_object is a nice method. I like it.. +1

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.