【问题标题】:How to merge two arrays of hashes如何合并两个哈希数组
【发布时间】:2017-09-26 21:25:11
【问题描述】:

我有两个哈希数组:

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 的回答一样。

标签: arrays ruby ruby-hash


【解决方案1】:

uniq 如果您以相反的顺序连接数组,则可以使用:

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

但它不会保留顺序。

【讨论】:

  • 这是最好的。
  • 顺序对于哈希来说并不重要。
  • @theTinMan ab 是数组。此外,使用 ruby​​ 哈希顺序可以保留,因此很重要。
  • 不,顺序并不重要。插入顺序通过散列保存,但创建散列并以所需的任何顺序从中提取值是微不足道的。在许多语言中,哈希不保持顺序,包括以前版本的 Ruby。在哈希保持这种顺序之前,每个人都知道如何通过对键进行排序来处理它们。
  • @theTinMan:Python 很快就会默认订购字典:twitter.com/raymondh/status/850102884972675072。很方便,何乐而不为呢?
【解决方案2】:
[a, b].map { |arr| arr.group_by { |e| e[:key] } }
      .reduce(&:merge)
      .flat_map(&:last)

这里我们使用hash[:key] 作为键来构建新的哈希,然后我们merge 他们用最后一个值覆盖所有内容并返回values

【讨论】:

  • reduce(&amp;:merge) 应该够了
  • @Ilya 没有想法 :) 不过我不在乎。
  • @mudasobwa 伙计,你为什么要混淆代码,我想它就是(b+a).group_by { |e| e[:key] }.values.map {|arr| arr.first}
  • @aqfaridi 你在阅读 ruby​​ 代码时遇到问题并不意味着它被某种方式混淆了。
  • @mudasobwa 伙计,我理解你的代码,但是你在一次操作中使用了两次 map,这使得它成为冗余操作,无论如何没问题。
【解决方案3】:

我会重建你的数据,因为哈希中有冗余键:

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] }
【解决方案4】:

使用Enumerable#group_byEnumerable#map

(b+a).group_by { |e| e[:key] }.values.map {|arr| arr.first}

【讨论】:

    【解决方案5】:

    如果您需要合并两个也应该合并的哈希数组并且有两个以上的键,那么下一个 sn-p 应该会有所帮助:

    [a, b].flatten
          .compact
          .group_by { |v| v[:key] }
          .values
          .map { |e| e.reduce(&:merge) }
    

    【讨论】:

      猜你喜欢
      • 2016-10-07
      • 1970-01-01
      • 1970-01-01
      • 2016-09-02
      • 1970-01-01
      • 2013-04-18
      • 2020-09-25
      • 1970-01-01
      相关资源
      最近更新 更多