См. Hash # merge для требований.
class Hash
def my_merge(h)
keys.each_with_object({}) do |k,g|
g[k] = if h.key?(k)
block_given? ? yield(k, self[k], h[k]) : h[k]
else
self[k]
end
end.tap { |g| (h.keys-keys).each { |k| g[k] = h[k] } }
end
end
h = { a: 1, b: 2, c: 3 }
g = { b: 3, c: 4, d: 5 }
h.my_merge(g) #=> {:a=>1, :b=>3, :c=>4, :d=>5}
h.merge(g) #=> {:a=>1, :b=>3, :c=>4, :d=>5}
h.my_merge(g) { |_,o,n| o+n } #=> {:a=>1, :b=>5, :c=>7, :d=>5}
h.merge(g) { |_,o,n| o+n } #=> {:a=>1, :b=>5, :c=>7, :d=>5}
merge
не возвращает массивы значений общих ключей, но для этого его можно использовать с конкретным блоком.:
h.my_merge(g) { |_,o,v| [o, v] } #=> {:a=>1, :b=>[2, 3], :c=>[3, 4], :d=>5}
h.merge(g) { |_,o,v| [o, v] } #=> {:a=>1, :b=>[2, 3], :c=>[3, 4], :d=>5}
Для читателей, незнакомых с Object # tap , без него мне нужно написать метод примерно так:
def my_merge(h)
g = keys.each_with_object({}) do |k,g|
g[k] = if h.key?(k)
block_given? ? yield(k, self[k], h[k]) : h[k]
else
self[k]
end
end
(h.keys-keys).each { |k| g[k] = h[k] }
g
end