根据 Ruby 中的唯一散列键比较数组及其内部散列的最有效方法

Most efficient way of comparing arrays with hashes inside them based on a unique hash key in Ruby

我有两个散列 hash_a 和 hash_b,它们实际上是数组,但里面有散列。这些散列具有唯一键。

hash_a = [
{:unique_key => 1, :data => 'data for A1'},
{:unique_key => 2, :data => 'data for A2'},
{:unique_key => 3, :data => 'data for A3'}
]

hash_b = [
{:unique_key => 1, :data => 'data for B1'},
{:unique_key => 2, :data => 'data for B2'},
{:unique_key => 4, :data => 'data for B4'},
{:unique_key => 5, :data => 'data for B5'}
]

现在我想找出 hash_a 和 hash_b 之间的区别,这样我就可以得到 hash_c 作为 hash_b 中存在的新哈希数组。 我基本上想要hash_b - hash_a

所以我想要 hash_c 的输出,hash_c 应该是这样的:

[
{:unique_key => 1, :data => 'data for A1'},
{:unique_key => 2, :data => 'data for A2'},
{:unique_key => 3, :data => 'data for A3'},
{:unique_key => 4, :data => 'data for B4'},
{:unique_key => 5, :data => 'data for B5'}
]

我试过这样的方法:

hash_c = hash_a
hash_b.each do |inner_bhash|
    found = 0

    hash_a.each do |inner_ahash|
        if(inner_ahash[:unique_key] == inner_bhash[:unique_key])
            found = 1
            break
        end
    end

    if(found==0)
        hash_c.push(inner_bhash)
    end
end

这是解决问题的方法,但我想要一个更好的方法。比如hashmap什么的,我也不知道。


此外,我可能只想查看新条目,即

[
  {:unique_key => 4, :data => 'data for B4'},
  {:unique_key => 5, :data => 'data for B5'}
]

我可以通过替换

在我的代码中做到这一点
hash_c = hash_a

hash_c = []

但我如何才能以同样的方式调整此要求?

使用 Hashes 你可以使用 merge 做你想做的事 - 所以通过将每个 Array 变成 Hash 你可以做以下事情:

hash_b.group_by { |e| e[:unique_key] }.
   merge(hash_a.group_by { |e| e[:unique_key] }).values.flatten
# => [{:unique_key=>1, :data=>"data for A1"}, 
#     {:unique_key=>2, :data=>"data for A2"}, 
#     {:unique_key=>4, :data=>"data for B4"}, 
#     {:unique_key=>5, :data=>"data for B5"}, 
#     {:unique_key=>3, :data=>"data for A3"}]

如果你只想拥有 hash_b 的条目(在 hash_a 中没有键),假设你已经有了上面的解决方案 - 你可以简单地 从结果中减去 hash_a

hash_b.group_by { |e| e[:unique_key] }.
  merge(hash_a.group_by { |e| e[:unique_key] }).values.flatten - hash_a
# => [{:unique_key=>4, :data=>"data for B4"}, 
#     {:unique_key=>5, :data=>"data for B5"}]

另一种更直接的方法是过滤掉 hash_b 中所有在 hash_a 中有条目的元素:

hash_b.select { |x| hash_a.none? { |y| x[:unique_key] == y[:unique_key] } }
# => [{:unique_key=>4, :data=>"data for B4"}, 
#     {:unique_key=>5, :data=>"data for B5"}]

您可以使用 Array#uniq 的形式来占用一个块。

 (hash_a + hash_b).uniq { |h| h[:unique_key] }
  #=> [{:unique_key=>1, :data=>"data for A1"}, {:unique_key=>2, :data=>"data for A2"},
  #    {:unique_key=>3, :data=>"data for A3"}, {:unique_key=>4, :data=>"data for B4"},
  #    {:unique_key=>5, :data=>"data for B5"}] 

引用文档,"self is traversed in order, and the first occurrence is kept."