寻找一种以特殊方式合并两个哈希数组的优雅方法:
new_data = [{"name" => "a"}, {"name" => "b"}, {"name" => "c"}]
old_data = [{"name" => "a", "data" => "extra1"}, {"name" => "d", "data2" => "extra"}]
result = [{"name" => "a", "data" => "extra1"}, {"name" => "b"}, {"name" => "c"}]
如果名称键匹配,结果必须包含new_data
的所有名称哈希值,只包含old_data
的额外数据。
我的第一次尝试就是这个,但它创建了一个额外的哈希:
def combine(new_data, old_data)
int = []
new_data.each do |s|
old_data.each do |e|
(int << (s.merge e)) if e["name"] == s["name"]
end
int << s
end
int
end
# => [{"name"=>"a", "data"=>"extra1"}, {"name"=>"a"}, {"name"=>"b"}, {"name"=>"c"}]
答案 0 :(得分:5)
一个单行,但在大型集合上可能不太高效。
new_data.map{ |e| e.merge(old_data.detect{ |e2| e2['name'] == e['name'] } || {}) }
答案 1 :(得分:1)
这有点棘手,但您可以通过从new_data
转换为查找哈希来解决它,然后迭代old_data
以合并内容:
new_data = [{"name" => "a"}, {"name" => "b"}, {"name" => "c"}]
old_data = [{"name" => "a", "data" => "extra1"}, {"name" => "d", "data2" => "extra"}]
# Transform into a lookup table using "name" as a key
lookup = Hash[new_data.collect { |v| [ v['name'], v ] }]
old_data.each do |data|
# Match based on "name"
found = lookup[data['name']]
next unless (found)
# If found, swap out the element with a merged version
# so the original is preserved as-is, not mangled.
lookup[data['name']] = found.merge(data)
end
lookup.values
# => [{"name"=>"a", "data"=>"extra1"}, {"name"=>"b"}, {"name"=>"c"}]
答案 2 :(得分:0)
<强>假设强>
我假设:
new_data
和old_data
"name"
的值都是唯一的; new_data
是一个包含一个键值对的哈希数组;和old_data
是一个包含至少两个键值对的哈希数组。<强>代码强>
def extract_elements(new_data, old_data)
(new_data+old_data).group_by { |h| h["name"] }.
values.
select { |a| a.size > 1 || a.first.size == 1 }.
map(&:last)
end
示例强>
new_data = [{"name" => "a"}, {"name" => "b"}, {"name" => "c"}]
old_data = [{"name" => "a", "data" => "extra1"},
{"name" => "d", "data2" => "extra"}]
extract_elements(new_data, old_data)
#=> [{"name"=>"a", "data"=>"extra1"}, {"name"=>"b"}, {"name"=>"c"}]
<强>解释强>
对于上面的示例:
a = (new_data+old_data)
#=> [{"name"=>"a"}, {"name"=>"b"}, {"name"=>"c"},
# {"name"=>"a", "data"=>"extra1"}, {"name"=>"d", "data2"=>"extra"}]
b = a.group_by { |h| h["name"] }
#=> {"a"=>[{"name"=>"a"}, {"name"=>"a", "data"=>"extra1"}],
# "b"=>[{"name"=>"b"}],
# "c"=>[{"name"=>"c"}],
# "d"=>[{"name"=>"d", "data2"=>"extra"}]}
c = b.values
#=> [[{"name"=>"a"}, {"name"=>"a", "data"=>"extra1"}],
# [{"name"=>"b"}],
# [{"name"=>"c"}],
# [{"name"=>"d", "data2"=>"extra"}]]
d = c.select { |a| a.size > 1 || a.first.size == 1 }
#=> [[{"name"=>"a"}, {"name"=>"a", "data"=>"extra1"}],
# [{"name"=>"b"}],
# [{"name"=>"c"}]]
e = d.map(&:last)
#=> [{"name"=>"a", "data"=>"extra1"},
# {"name"=>"b"},
# {"name"=>"c"}]
<强>限制性条款强>
这需要Ruby v1.9 +,因为它需要为散列b
维护密钥插入顺序。对于早期版本,请替换:
map(&:last)
使用:
map { |h| h.max_by(&:size) }