Home > Software design >  Copy hash values from a hash into another only where keys exist in both hashes?
Copy hash values from a hash into another only where keys exist in both hashes?

Time:06-27

How can the values from one hash be copied into another, but only for the keys that exist in both hashes?

Minimal example

h1 = {a: 10, b: 20, c: 30}
h2 = {a: nil, c: nil}

## desired result
{a: 10, c: 30}

I've solved with a 'manual' approach - i.e. {a: h1[:a], c: h1[:c]} - but it's verbose and looks worse the more keys there are. I'm sure there's something (much) more elegant?

CodePudding user response:

The "manual" approach with a loop would look something like this

h1.each do |k, v|
  h2[k] = v if h2.include? k
end

If your goal is to create a new hash, rather than modifying an existing one, you can use filter (called select in older versions of Ruby)

h1.filter { |k, v| h2.include? k }

Or if you want to modify h1 to only have the keys from k2, you can use filter! (called select! in older versions), which works like filter but modifies in-place.

h1.filter! { |k, v| h2.include? k }

CodePudding user response:

One way is to use the form of Hash#merge that takes a block that computes the values of keys that are present in both hashes being merged:

h1 = {a: 10, b: 20, c: 30}
h2 = {a: nil, c: nil}
h2.merge(h2) { |k,*| h1[k] }
  #=> {:a=>10, :c=>30}

As h2 is merged with itself, the block is invoked for every key.

One advantage of this approach is that it avoids the need for a linear search of keys in h2 for each key in h1. By contrast, key lookups (to obtain h1[k]) are quite fast.

  •  Tags:  
  • ruby
  • Related