Arrays Ruby中哈希数组的选择性合并
我有两个包含哈希的数组:Arrays Ruby中哈希数组的选择性合并,arrays,ruby,hash,Arrays,Ruby,Hash,我有两个包含哈希的数组: a = [ {:umc=>"11VE", :title=>"FOOBARS"}, {:umc=>"1973", :title=>"ZOOBARS"}, {:umc=>"1140", :title=>"TINYBAR"}, ] b = [ {:umc=>"11VE", :code=>"23"}, {:umc=>"10EE", :code=>"99"}, {:umc=>"1140",
a = [
{:umc=>"11VE", :title=>"FOOBARS"},
{:umc=>"1973", :title=>"ZOOBARS"},
{:umc=>"1140", :title=>"TINYBAR"},
]
b = [
{:umc=>"11VE", :code=>"23"},
{:umc=>"10EE", :code=>"99"},
{:umc=>"1140", :code=>"44"},
{:umc=>"1973", :code=>"55"},
]
并希望有选择地使用哈希将它们合并到另一个数组中,如下所示:
c = [
{:umc=>"11VE", :title=>"FOOBARS", :code=>"23"},
{:umc=>"1973", :title=>"ZOOBARS", :code=>"55"},
{:umc=>"1140", :title=>"TINYBAR"} :code=>"44"},
]
bb = b.select { |f| a.any? { |h| h[:umc] == f[:umc] } }
#=> [{:umc=>"11VE", :code=>"23"},
# {:umc=>"1140", :code=>"44"},
# {:umc=>"1973", :code=>"55"}]
(a + bb).group_by { |g| g[:umc] }.map { |_,v| v.reduce(:merge) }
#=> [{:umc=>"11VE", :title=>"FOOBARS", :code=>"23"},
# {:umc=>"1973", :title=>"ZOOBARS", :code=>"55"},
# {:umc=>"1140", :title=>"TINYBAR", :code=>"44"}]
我正在使用代码
combo=(a+b).group_by{|h| h[:umc]}.map{|k,v| v.reduce(:merge)}
这很好地合并了两个数组,但我希望结果只包括第一个数组中出现的项
作为第二个想法,最好能有两个结果,一个是由两个初始数组组合而成的项,另一个是包含第一个数组中的元素但不在第二个数组中的元素。不是很优雅,但它在计算方面应该相当有效,因为它平均是O(n+m)。我怀疑你能比这更快得到它。缺点是它会占用大量空间
def selective_merge(a, b)
merged = {}
a.each {|v| merged[v[:umc]] = [v[:umc], v[:title]]}
b.each {|v| merged[v[:umc]] = merged[v[:umc]] << v[:code] if merged[v[:umc]]}
merged.map {|k,v| {:umc => v[0], :title => v[1], :code => v[2]}}
end
def选择性_合并(a、b)
合并={}
a、 每个{v |合并的[v[:umc]=[v[:umc],v[:title]}
b、 每个{v | merged[v[:umc]]=merged[v[:umc]]v[0],:title=>v[1],:code=>v[2]}
结束
您可以按如下方式修改代码:
c = [
{:umc=>"11VE", :title=>"FOOBARS", :code=>"23"},
{:umc=>"1973", :title=>"ZOOBARS", :code=>"55"},
{:umc=>"1140", :title=>"TINYBAR"} :code=>"44"},
]
bb = b.select { |f| a.any? { |h| h[:umc] == f[:umc] } }
#=> [{:umc=>"11VE", :code=>"23"},
# {:umc=>"1140", :code=>"44"},
# {:umc=>"1973", :code=>"55"}]
(a + bb).group_by { |g| g[:umc] }.map { |_,v| v.reduce(:merge) }
#=> [{:umc=>"11VE", :title=>"FOOBARS", :code=>"23"},
# {:umc=>"1973", :title=>"ZOOBARS", :code=>"55"},
# {:umc=>"1140", :title=>"TINYBAR", :code=>"44"}]
但这样计算bb
会更有效:
require 'set'
umc_a_vals = a.map { |g| g[:umc] }.to_set
#=> #<Set: {"11VE", "1973", "1140"}>
bb = b.select { |f| umc_a_vals.include(f[:umc]) }
#=> [{:umc=>"11VE", :code=>"23"},
# {:umc=>"1140", :code=>"44"},
# {:umc=>"1973", :code=>"55"}]
f
的计算与您的代码非常相似,因此我认为不需要解释
我们现在合并散列:
{ g[:umc]=g }
#=> { "11VE"=>{:umc=>"11VE", :code=>"23"} }
如果h
有一个键“11VE”
,则进入h
。为此,我们使用(也称为merge!
)的形式,该形式使用块:
{ |_,o,n| o.merge(n) }
确定合并的两个哈希中存在的键的值
块变量等于:
_ #=> "11VE"
o #=> {:umc=>"11VE", :title=>"FOOBARS"}
n #=> {:umc=>"11VE", :code=>"23"}
因此,区块计算结果为:
o.merge(n)
#=> {:umc=>"11VE", :title=>"FOOBAR, :code=>"23"}
这是h[:umc]
的更新值
旁白:我使用局部变量\uu
作为键的值,以提请注意在块计算中没有使用它这一事实。变量o
和n
通常分别用于表示“旧”值和“新”值
从b
的剩余值构造的散列的合并到h
中也是类似的
最后一步是提取h
的值
作为第二个示例,假设:
a = [
{:umc=>"11VE", :title=>"FOOBARS"},
{:umc=>"11VE", :title=>"ZOOBARS", :author=>"Billy-Bob"},
{:umc=>"1140", :title=>"TINYBAR"}
]
我们获得:
f = a.each_with_object({}) { |g,h| h.update(g[:umc]=>g) { |_,o,n| o.merge(n) } }
#=> {"11VE"=>{:umc=>"11VE", :title=>"ZOOBARS", :author=>"Billy-Bob"},
# "1140"=>{:umc=>"1140", :title=>"TINYBAR"}}
b.each_with_object(f) do |g,h|
(h.update(g[:umc]=>g) { |_,o,n| o.merge(n) }) if h.key?(g[:umc])
end.values
#=> [{:umc=>"11VE", :title=>"ZOOBARS", :author=>"Billy-Bob", :code=>"23"},
# {:umc=>"1140", :title=>"TINYBAR", :code=>"44"}]
Cary提出了一种“更具可读性”的方式来表示合并,另外,无论我们是否希望对初始a
数组进行变异,我们都应该dup
它的元素:
b.reduce(a.map(&:dup)) do |memo, e|
ae = memo.detect { |ae| ae[:umc] == e[:umc] }
ae.merge!(e) if ae
memo
end
试试这个
# @a - Pivot array(elements that will be in result array)
# @b - Array which contains intersecting elements
# @group - attribute name, which identify similarity of elements
def c_join(a, b, group)
result = []
a.each do |a_i|
similar = b.detect{ |b_i| b_i[group] == a_i[group] }
result << a_i.merge(similar)
end
result
end
结果
[
{:umc=>"11VE", :title=>"FOOBARS", :code=>"23"},
{:umc=>"1973", :title=>"ZOOBARS", :code=>"55"},
{:umc=>"1140", :title=>"TINYBAR", :code=>"44"}
]
怎么样
:umc=>“10EE”
?很抱歉,10EE不应该出现在第一个数组中。毋庸置疑,实际数据超过10000项。感谢您的关注。您还可以通过传入select操作使其更通用,并使其在哈希中使用更多键。这是一个很好的答案,但我对Ruby和其他方面都还是新手。两个初始数组可能有任意数量的元素,因此如果element:umc匹配,我想调整代码以合并两个哈希的所有元素,而不必指定它们。这是一个很好的解决方案,但应该注意它会变异a
的元素。依我看,如果把第一行分成两行,后者是ae.merge,那就更好了!(e) 如果ae
。您还可以将b.reduce(a)
更改为(a+b)。如果a
中的两个哈希值对于:umc
相同,则reduce({})
。(这是我犯的一个错误,被OP标记出来。)@CarySwoveland我添加了.dup
,以避免初始数组的变异,谢谢。关于你的第二个评论,我没有得到一个要点。结果不会以任何方式切割a
,它只会将其与b
@CarySwoveland合并-第一个提议的代码实际上做了我想要的一切,或者至少我认为它做了。我的计划是查看所有其他解决方案,直到我理解为什么其中一些解决方案只包含以下结果:umc在两个阵列中都匹配。此解决方案按其应做的方式进行合并,并在根据匹配添加b中的元素时保持a。谢谢你们的解决方案和教育。@berlin欢迎你们。请注意减少a
(正如Cary之前指出的那样,由于inplacemerge!
,我们改变了初始a数组)和a.dup
之间的区别,后者不会改变任何初始输入。后者似乎更可靠。您的第二个示例运行得很好,但它似乎丢弃了a中与b中没有对应匹配的任何元素。我需要保留a的所有元素,不管与b的匹配如何。我只是不想要a中没有的b。我正在慢慢地研究每一个建议的解决方案,主要是为了让自己加快使用ruby(2.0版)的速度。(读者:我提供的第二种方法的问题是,如果g
和h
是a
和g[:umc]=h[:umc]
的元素,那么第一个散列将被第二个散列覆盖)。我已经修复了它,并给出了另一个例子。
[
{:umc=>"11VE", :title=>"FOOBARS", :code=>"23"},
{:umc=>"1973", :title=>"ZOOBARS", :code=>"55"},
{:umc=>"1140", :title=>"TINYBAR", :code=>"44"}
]