Copy hash values from a hash into another only where keys exist in both hashes?

Viewed 67

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?

2 Answers

You can do that as follows.

h1 = { a: 10, b: 20, c: 30 }
h2 = { a: nil, c: nil, d: nil }
h1.slice(*h2.keys)
  #=> {:a=>10, :c=>30}

See Hash#slice.

Note that the example above differs from the one in the question in that I've added a key to h2 (:d) that is not present in h1.

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 }
Related