如何合并两个哈希没有新的键
我怎么能合并两个哈希导致没有新的密钥,这意味着合并会合并两个哈希中存在的密钥?
例如,我想要以下内容:
h = {:foo => "bar"} j = {:foo => "baz", :extra => "value"} puts h.merge(j) # {:foo => "baz"}
我正在寻找一种非常干净的方法,因为我当前的实现非常混乱。
您可以从第二个哈希中删除不在第一个哈希中的键,然后合并:
h.merge j.select { |k| h.keys.include? k }
与我编辑的替代方案不同,如果您决定将其更改为merge!
,这是安全的merge!
或update
。
如果你正在使用activesupport(rails的一部分),你可以在Hash
上利用2个额外的方法:
-
Hash#slice
将所需的键作为单独的参数(不是键数组),并返回一个新哈希,只包含您要求的键。 -
Hash#except
使用与slice
相同的参数,但返回带有不在参数中的键的新哈希。
首先加载activesupport:
require 'active_support/core_ext'
仅合并其键已经在h
j
的条目(即修改,但不添加任何或删除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
剩余物不在j
:
h.except(*j.keys)
如果您希望字符串和符号键访问被视为等效,您可能还想使用activesupport的HashWithIndifferentAccess
。
请注意,上述示例均未改变原始哈希值; 而是返回新的哈希值。
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] }
[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
更加个性化的方式是:
h = {"foo"=> "bar"} j = {"foo" => "baz", "extra" => "value"} k = h.merge(j) result: {"foo"=>"baz", "extra"=>"value"}
这里第二个哈希中的键“foo”覆盖了第一个哈希中的“foo”。但是如果你想保留旧值,即bar,或者你想保留新值即“baz”? 你可以这样做:
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"}