如何合并两个哈希没有新的键

时间:2011-01-28 05:12:40

标签: ruby hash key duplicates

如何合并两个导致没有新密钥的哈希,这意味着合并会合并两个哈希中存在的密钥?

例如,我想要以下内容:

h = {:foo => "bar"}
j = {:foo => "baz", :extra => "value"}

puts h.merge(j)    # {:foo => "baz"}

我正在寻找一种非常干净的方法,因为我当前的实现非常混乱。

5 个答案:

答案 0 :(得分:14)

您可以从第二个哈希中删除不在第一个哈希中的键,然后合并:

h.merge j.select { |k| h.keys.include? k }

与我已编辑的替代方案不同,如果您决定将其更改为merge!update,则此选项很安全。

答案 1 :(得分:8)

Yjerem的答案适用于Ruby 1.9,但不适用于1.8.x.在1.8.x中,Hash#select方法返回一个数组。 Hash#reject返回哈希值。

h.reject { |k,v| !j.keys.include? k }

如果您只想保留具有相同值的键值对,则可以执行以下操作:

h.reject { |k,v| j[k] != h[k] }

边缘案例有nils。如果你在nash中存储nils,那么你必须这样做:

h.reject { |k,v| !j.has_key? k or j[k] != h[k] }

答案 2 :(得分:8)

如果你正在使用activesupport(rails的一部分),你可以在Hash上利用2个额外的方法:

  • Hash#slice将所需的键作为单独的参数(不是键数组),并返回一个新哈希,只包含您要求的键。
  • Hash#except使用与slice相同的参数,但返回带有不在参数中的键的新哈希。

首先加载activesupport:

require 'active_support/core_ext'

仅合并其密钥已在j中的h条目(即修改,但不在h中添加或删除条目):

h.merge(j.slice(*h.keys))

示例:

ignore_new = ->(h, j) { h.merge(j.slice(* h.keys)) }
ignore_new.({a: 1, b: 2, c: 3}, {b: 10, c: 11, d: 12})
# => {:a=>1, :b=>10, :c=>11}

获取j以外的h残留物:

j.except(*h.keys)

<强>加成:

如果你想要真正的交集,意味着你想要一个只有两个哈希之间共同的键的结果,那就这样做:

h.merge(j).slice(* ( h.keys & j.keys ) )

示例:

intersect = ->(h, j) { h.merge(j).slice(* (h.keys & j.keys) ) }
intersect.({a: 1, b: 2, c: 3}, {b: 10, c: 11, d: 12})
# => {:b=>10, :c=>11}

以及来自h的{​​{1}}剩余的剩余信息:

j

如果你想要字符串和放大器,你可能还想使用activesupport的h.except(*j.keys) 。符号密钥访问被认为是等效的。

请注意,上述示例均未改变原始哈希值;而是返回新的哈希值。

答案 3 :(得分:0)

[h].inject({}) { |m,e| e.merge(j) { |k,o,n| m[k] = n }; m}

[{}].inject(h) { |m,e| m.merge(j) { |k,o,n| e[k] = n }; e}

(可能是最好的,但在技术上不是单个表达式)......

t = {}; h.merge(j) { |k,o,n| t[k] = n }; t

答案 4 :(得分:-1)

更加个性化的方式是:

 h = {"foo"=> "bar"}

 j = {"foo" => "baz", "extra" => "value"}


 k = h.merge(j)
result:  {"foo"=>"baz", "extra"=>"value"}

这里有关键&#34; foo&#34;在第二个哈希中覆盖&#34; foo&#34;在第一个哈希。但是如果你想保留旧的值,如bar,或者如果你想保留新值,即&#34; baz&#34;?你可以这样做:

  k = h.merge(j){|key, old, new| old}
 result: {"foo"=>"bar", "extra"=>"value"}


k = h.merge(j){|key, old, new| new}

result: {"foo"=>"baz", "extra"=>"value"}