如何合并两个哈希数组

14

我有两个哈希数组:

a = [
  {
    key: 1,
    value: "foo"
  },
  {
    key: 2,
    value: "baz"
  }
]

b = [
  {
    key: 1,
    value: "bar"
  },
  {
    key: 1000,
    value: "something"
  }
]

我想将它们合并成一个哈希数组,基本上就是a + b,但我希望b中任何重复的键都会覆盖a中的键。在这种情况下,ab都包含键1,我希望最终结果具有b的键值对。

以下是预期结果:

expected = [
  {
    key: 1,
    value: "bar"
  },
  {
    key: 2,
    value: "baz"
  },
  {
    key: 1000,
    value: "something"
  }
]

我想知道是否有更简洁的方法,尽管我已经解决了问题。

hash_result = {}
a.each do |item|
  hash_result[item[:key]] = item[:value]
end

b.each do |item|
  hash_result[item[:key]] = item[:value]
end

result = []
hash_result.each do |k,v|
  result << {:key => k, :value => v}
end

puts result

puts expected == result # prints true

你想要哈希的功能:你想要唯一的键,并且你想要一个更容易合并数据的方法。所以只需使用哈希,就像@Ilya的答案中所示。 - Eric Duminil
5个回答

16

uniq 如果你按照相反的顺序连接这些数组,就可以使用它:

(b + a).uniq { |h| h[:key] }
#=> [
#     {:key=>1, :value=>"bar"},
#     {:key=>1000, :value=>"something"},
#     {:key=>2, :value=>"baz"}
#   ]

然而,它并不保留顺序。


这是最好的。 - Aleksei Matiushkin
哈希表中的顺序并不重要。 - the Tin Man
1
@theTinMan ab 是数组。此外,使用 Ruby 哈希表可以保留顺序,因此非常重要。 - Aleksei Matiushkin
1
不,顺序并不重要。哈希表保留插入顺序,但是可以轻松创建哈希表并按任意顺序提取值。在许多编程语言中,哈希表不保持顺序,包括以前的 Ruby 版本。在哈希表保持顺序之前,每个人都知道如何通过对键进行排序来处理它们。 - the Tin Man
@theTinMan:Python很快就会默认支持有序字典了:https://twitter.com/raymondh/status/850102884972675072。这非常方便,为什么不用呢? - Eric Duminil

2
[a, b].map { |arr| arr.group_by { |e| e[:key] } }
      .reduce(&:merge)
      .flat_map(&:last)

这里我们使用 hash[:key] 作为一个键来构建新的哈希表,然后我们使用 merge 方法将它们合并在一起,最后一个值会覆盖之前所有的值,并返回 values


1
reduce(&:merge) 应该足够了。 - Stefan
@Ilya 没有想法 :) 不过我不在意。 - Aleksei Matiushkin
@mudasobwa 兄弟,你为什么要混淆这段代码呢?我认为简单来说就是 (b+a).group_by { |e| e[:key] }.values.map {|arr| arr.first} - aqfaridi
@aqfaridi,你阅读 Ruby 代码有困难并不意味着它被混淆了。 - Aleksei Matiushkin
@mudasobwa 哥们,我懂你的代码了,但是你在单个操作中使用了两次 map,这使得操作冗余了,不过没关系。 - aqfaridi

1
我会重新构建您的数据,因为哈希表中存在冗余的键:
thin_b = b.map { |h| [h[:key], h[:value]] }.to_h
#=> {1=>"bar", 1000=>"something"}
thin_a = b.map { |h| [h[:key], h[:value]] }.to_h
#=> {1=>"bar", 1000=>"something"}

然后您可以只使用Hash#merge
thin_a.merge(thin_b)
#=> {1=>"bar", 2=>"baz", 1000=>"something"}

但是,如果您希望,您可以获得与问题中提到的完全相同的结果:

result.map { |k, v| { key: k, value: v } }
#=> [{:key=>1, :value=>"bar"}, 
#    {:key=>2, :value=>"baz"}, 
#    {:key=>1000, :value=>"something"}]

这不完全是 OP 所要求的,但这可能仍然是最好的答案。另一种选择是:(a+b).each_with_object({}){ |s, h| h[s[:key]] = s[:value] } - Eric Duminil

0
如果您需要合并两个哈希数组,这些数组也应该被合并,并且有超过两个键,则下面的代码片段应该会有所帮助:
[a, b].flatten
      .compact
      .group_by { |v| v[:key] }
      .values
      .map { |e| e.reduce(&:merge) }

0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接