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

elm*_*lmt 14 ruby hash key duplicates

我怎么能合并两个哈希值,导致没有新的键,这意味着合并会合并两个哈希中存在的键?

例如,我想要以下内容:

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

puts h.merge(j)    # {:foo => "baz"}
Run Code Online (Sandbox Code Playgroud)

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

Jer*_*ten 14

You could remove keys that weren't in the first hash from the second hash, then merge:

h.merge j.select { |k| h.keys.include? k }
Run Code Online (Sandbox Code Playgroud)

Unlike my edited-out alternative, this is safe if you decide to change it to a merge! or update.

  • @elmt,@ yjerem,@ ron-gejman注意`h.keys.include?(k)`与`h.key?(k)`相同但后者应该表现更好,因为它避免了线性搜索`keys`数组. (2认同)

Kel*_*vin 9

如果您正在使用activesupport(rails的一部分),您可以利用以下两种额外方法Hash:

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

首先加载activesupport:

require 'active_support/core_ext'
Run Code Online (Sandbox Code Playgroud)

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

h.merge(j.slice(*h.keys))
Run Code Online (Sandbox Code Playgroud)

例:

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}
Run Code Online (Sandbox Code Playgroud)

获得从剩菜j是不是在h:

j.except(*h.keys)
Run Code Online (Sandbox Code Playgroud)

奖金:

如果你想要真正的交集,意味着你想要一个只有两个哈希之间共同的键的结果,那么执行以下操作:

h.merge(j).slice(* ( h.keys & j.keys ) )
Run Code Online (Sandbox Code Playgroud)

例:

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}
Run Code Online (Sandbox Code Playgroud)

剩下的东西h不在j:

h.except(*j.keys)
Run Code Online (Sandbox Code Playgroud)

HashWithIndifferentAccess如果您希望字符串和符号密钥访问被视为等效,您可能还想使用activesupport .

请注意,以上示例均未更改原始哈希值; 而是返回新的哈希值.


Ron*_*man 8

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

h.reject { |k,v| !j.keys.include? k }
Run Code Online (Sandbox Code Playgroud)

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

h.reject { |k,v| j[k] != h[k] }
Run Code Online (Sandbox Code Playgroud)

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

h.reject { |k,v| !j.has_key? k or j[k] != h[k] }
Run Code Online (Sandbox Code Playgroud)