我有一个哈希,我需要将其与哈希数组进行比较。
例如:
# Array of Hashes to compare another hash against
@stored_hash = [
{:a => 1, :b => 2, :c => {:d => 3, :e => 4, :f => 5}},
{:a => 1, :b => 2, :c => {:d => 3, :e => 4, :f => 5}},
{:a => 1, :b => 2, :c => {:d => 3, :e => 4, :f => 5}},
]
# Hash to compare to Array of Hashes
@sample_hash = {:d => 3, :e => 4, :f => 5}
我正在寻找@sample_hash
中与所有@stored_hashes
我可以将单个哈希与另一个哈希进行比较,如此
res = @sample_hash.keys.select { |k| @stored_hash.key?(k) }
但我不能让它为一系列哈希工作。帮助赞赏。
修改
这是我到目前为止所尝试过的。
res = @sample_hash.keys.select { |k| @stored_hash.map(&:keys).include?(k) }
这似乎只是拖延程序(我正在使用非常大的数据集)
我也试过这个:
res = @sample_hash.keys.select { |k| @stored_hash.map { |x| x.key?(k) } }
哪会返回结果,但如果我反过来:
res = @sample_hash.keys.reject { |k| @stored_hash.map { |x| x.key?(k) } }
我没有得到任何结果(我知道哈希中有常见和非常见键的事实)
答案 0 :(得分:2)
我们可以分两步完成。
第1步
stored_hash = [
{ :a => 1, :b => 2, :c => { :d => 3, :e => 4, :f => 5 } },
{ :a => 1, :b => 2, :c => { :d => 3, :e => 4, :g => 5 } },
{ :a => 1, :b => 2, :c => { :d => 3, :e => 4, :h => 5 } },
]
请注意,我稍微更改了stored_hash
。
def all_keys_all_hashes(arr)
arr.each_with_object([]) { |h,keys| keys.concat(all_keys(h)) }.uniq
end
def all_keys(h)
h.each_with_object([]) do |(k,v),arr|
arr << k
arr.concat(all_keys(v)) if v.is_a? Hash
end
end
keys = all_keys_all_hashes(stored_hash)
#=> [:a, :b, :c, :d, :e, :f, :g, :h]
第2步
sample_hash = {:d => 3, :e => 4, :f => 5, :z => 99 }
sample_hash.keys & keys
#=> [:d, :e, :f]
<强>附录强>
如果您遇到类似这样的问题,那么这是一个“快速和肮脏”的方式来获取stored_hash
中的所有密钥,前提是它们都是符号,字符串或自然数字。方法是将数组转换为字符串,然后使用正则表达式提取键,然后进行一些处理。
首先,为了处理更一般的情况,让我们修改stored_hash
的前两个元素中的每一个中的第一个键:
stored_hash = [
{"a" => 1, :b => 2, :c => {:d => 3, :e => 4, :f => 5}},
{ 99 => 1, :b => 2, :c => {:d => 3, :e => 4, :f => 5}},
{ :a => 1, :b => 2, :c => {:d => 3, :e => 4, :f => 5}},
]
你可以这样:
stored_hash.to_s.scan(/[{,]\s*\K[^{,]+?(?==>)/).uniq.map do |s|
case
when (s[0] == ?:) then s[1..-1].to_sym
when (s =~ /^\d+$/) then s.to_i
else s.gsub(?", '')
end
end
#=> ["a", :b, :c, :d, :e, :f, 99, :a]
\K
指示Ruby匹配之前的内容,但不将其包含在它保留的匹配中。当前一个匹配是可变长度(\s*
)时,它特别方便,因为正向外观不能用于可变长度匹配。
这不能正确处理带引号的符号(例如,:"text"
),但修改正则表达式来处理这种情况并不困难。
以下是步骤:
str = stored_hash.to_s
#=> "[{\"a\"=>1, :b=>2, :c=>{:d=>3, :e=>4, :f=>5}}, " +
# "{99=>1, :b=>2, :c=>{:d=>3, :e=>4, :f=>5}}, " +
# "{:a=>1, :b=>2, :c=>{:d=>3, :e=>4, :f=>5}}]"
(我已将字符串分成三部分,因此无需使用水平滚动即可读取。)
a1 = str.scan(/[{,]\s*\K[^{,]+?(?==>)/)
#=> ["\"a\"", ":b", ":c", ":d", ":e", ":f",
# "99", ":b", ":c", ":d", ":e", ":f",
# ":a", ":b", ":c", ":d", ":e", ":f"]
a2 = a1.uniq
#=> ["\"a\"", ":b", ":c", ":d", ":e", ":f", "99", ":a"]
a2.map do |s|
case
when (s[0] == ?:) then s[1..-1].to_sym
when (s =~ /^\d+$/) then s.to_i
else s.gsub(?", '')
end
end
#=> ["a", :b, :c, :d, :e, :f, 99, :a]