我正在尝试组合两个哈希数组arr1和arr2:
arr1 = [{"id"=>1, "a"=>1, "c"=>2}, {"id"=>2, "a"=>1}]
arr2 = [{"id"=>1, "a"=>10, "b"=>20}, {"id"=>3, "b"=>2}]
我希望结果包括两个数组中的所有元素,但那些具有相同值的"id"键,应该被合并如果一个键同时存在于两个哈希中,它应该从arr2中选择,否则,它只会从该键存在的哈希中选择值。因此,上述示例的组合将是:
combined = [
{"id"=>1, "a"=>10, "b"=>20, "c"=>2}, # "id"=>1 exists in both, so they are merged
{"id"=>2, "a"=>1},
{"id"=>3, "b"=>2}
]
下面的代码可以工作,但我是Ruby新手,我相信有更好的方法来做到这一点。你能提供一种更红宝石的方式吗?
combined = []
# merge items that exist in both and add to combined
arr1.each do |a1|
temp = arr2.select {|a2| a2["id"] == a1["id"]}[0]
if temp.present?
combined << temp.reverse_merge(a1)
end
end
# Add items that exist in arr1 but not in arr2
arr1.each do |a1|
if arr2.pluck("id").exclude? a1["id"]
combined << a1
end
end
# Add items that exist in arr2 but not in arr1
arr2.each do |a2|
if arr1.pluck("id").exclude? a2["id"]
combined << a2
end
end
我假设arr1
,g
和h
中没有两个元素(哈希值)具有g["id"] == h["id"]
的属性。
在这种情况下,可以这样写:
(arr1 + arr2).each_with_object(Hash.new { |h,k| h[k] = {} }) { |g,h|
h[g["id"]].update(g) }.values
#=> [{"id"=>1, "a"=>10, "c"=>2, "b"=>20}, {"id"=>2, "a"=>1},
# {"id"=>3, "b"=>2}]
注意:
(arr1 + arr2).each_with_object(Hash.new { |h,k| h[k] = {} }) { |g,h|
h[g["id"]].update(g) }
#=> {1=>{"id"=>1, "a"=>10, "c"=>2, "b"=>20}, 2=>{"id"=>2, "a"=>1},
# 3=>{"id"=>3, "b"=>2}}
如果定义了哈希:
h = Hash.new { |h,k| h[k] = {} }
则,可能在向h
添加密钥之后,如果h
没有密钥k
,则执行h[k] = {}
并返回空散列。参见Hash::new的形式,它接受一个块。参见Hash#update(又名Hash#merge!
)。
也可以这样写:
(arr1 + arr2).each_with_object({}) { |g,h| (h[g["id"]] ||= {}).update(g) }.values
#=> {1=>{"id"=>1, "a"=>10, "c"=>2, "b"=>20}, 2=>{"id"=>2, "a"=>1},
# 3=>{"id"=>3, "b"=>2}}
另一种方法是使用Emumerable#group_by,其中分组是基于键"id"
的值:
(arr1 + arr2).group_by { |h| h["id"] }.values.map { |a| a.reduce(&:merge) }
#=> [{"id"=>1, "a"=>10, "c"=>2, "b"=>20}, {"id"=>2, "a"=>1}, {"id"=>3, "b"=>2}]