我试图过滤嵌套的哈希并提取各种键和值。这是我正在查看的哈希:
exp = {
fam: {cty: "bk", ins: 3},
spec: {cty: "man", ins: 2},
br: {cty: "qns", ins: 1},
aha: {cty: "man", ins: 0}
}
我试图找到cty
为"man"
的所有哈希密钥。我想运行结果为以下哈希的东西:
e = {
spec: {cty: "man", ins: 2},
aha: {cty: "man", ins: 0}
}
我尝试了这个,看起来它几乎可以工作:
exp.each do |e, c, value|
c = :cty.to_s
value = "man"
if e[c] == value
puts e
end
end
但我得到的结果是:
=> true
而不是我正在寻找的东西:
e = {
spec: {cty: "man", ins: 2},
aha: {cty: "man", ins: 0}
}
答案 0 :(得分:3)
首先,你需要了解哈希迭代会给你什么。
考虑一下:
exp = {
fam: {cty: "bk", ins: 3},
spec: {cty: "man", ins: 2},
br: {cty: "qns", ins: 1},
aha: {cty: "man", ins: 0}
}
exp.map { |e, c, value| [e, c, value] }
# => [[:fam, {:cty=>"bk", :ins=>3}, nil], [:spec, {:cty=>"man", :ins=>2}, nil], [:br, {:cty=>"qns", :ins=>1}, nil], [:aha, {:cty=>"man", :ins=>0}, nil]]
这基本上就是你在循环时所做的事情,而Ruby传递了键/值对。您告诉Ruby在e
中提供当前哈希值,c
中的当前哈希值,并且由于没有传递任何其他内容,因此{{1} }参数变为value
。
相反,您需要一个用于键的块变量,一个用于值:
nil
请注意,nil值已消失。
考虑到这一点重写您的代码,并为简单起见重构:
exp.map { |k, v| [k, v] }
# => [[:fam, {:cty=>"bk", :ins=>3}], [:spec, {:cty=>"man", :ins=>2}], [:br, {:cty=>"qns", :ins=>1}], [:aha, {:cty=>"man", :ins=>0}]]
现在它返回了你想要的键,所以很容易抓住整个哈希。 select
是您尝试查找特定内容时使用的合适方法:
exp = {
fam: {cty: 'bk', ins: 3},
spec: {cty: 'man', ins: 2},
br: {cty: 'qns', ins: 1},
aha: {cty: 'man', ins: 0}
}
exp.each do |k, v|
if v[:cty] == 'man'
puts k
end
end
# >> spec
# >> aha
旧版本的Ruby没有维护散列迭代器的哈希输出,所以我们必须强制回哈希:
exp = {
fam: {cty: 'bk', ins: 3},
spec: {cty: 'man', ins: 2},
br: {cty: 'qns', ins: 1},
aha: {cty: 'man', ins: 0}
}
e = exp.select { |k, v| v[:cty] == 'man' }
# => {:spec=>{:cty=>"man", :ins=>2}, :aha=>{:cty=>"man", :ins=>0}}
答案 1 :(得分:2)
e = {}
exp.each do |k,v|
if v[:cty] == "man"
e[k] = v
end
end
p e
甚至
e = exp.select do |k,v|
v[:cty] == "man"
end
答案 2 :(得分:0)
正如Tin Man指出的那样,在迭代哈希时,有两个参数可以传递给一个块(本例中为do
和end
之间的代码)---一个用于它的关键和其他价值。
迭代哈希(并打印出它的值)
h = { a: "hello", b: "bonjour", c: "hola" }
使用.each
方法,您可以执行以下操作:
h.each do |key, value|
puts value
end
结果将是:
hello
bonjour
hola
=> {:a=>"hello", :b=>"bonjour", :c=>"hola"}
请注意,“返回”值是我们迭代的哈希值,它在ruby中计算为true
。 (nil
或false
以外的任何内容都将在Ruby中评估为true
。请参阅What evaluates to false in Ruby?)
这很重要,因为您在代码中获得true
的原因(实际上应该是{:fam=>{:cty=>"bk", :ins=>3}, :spec=>{:cty=>"man", :ins=>2}, :br=>{:cty=>"qns", :ins=>1}, :aha=>{:cty=>"man", :ins=>0}}
),而不是您想要的解析哈希是.each
返回的值散列的方法是散列本身(评估为true
)。
这就是为什么osman创建了一个空哈希e = {}
,以便在哈希的每次迭代中,我们可以使用我们想要的键和值填充新创建的哈希e
。
这解释了为什么他能做到:
e = exp.select do |k,v|
v[:cty] == "man"
end
这里的代码依赖于select
方法能够返回带有我们想要的键和值的新哈希(而不是像.each
方法那样的原始哈希)。
但如果你这样做
e = exp.each do |k,v|
v[:cty] == "man"
end
变量e
将被分配原始哈希exp
本身,这不是我们想要的。因此,了解应用方法时返回值的内容非常重要。
有关返回值(以及一般Ruby)的更多信息,我强烈推荐LaunchSchool“Ruby编程简介”(https://launchschool.com/books/ruby)中的免费电子书。这不仅帮助我认识到返回值的重要性,而且还为我提供了一般性的Ruby prigramming的坚实基础,如果您计划学习Ruby on Rails(我现在正在做的话),这非常有用。) / p>
答案 3 :(得分:0)
挖掘嵌套哈希的最简单方法是: -
class Hash
def deep_find(key, object=self, found=nil)
if object.respond_to?(:key?) && object.key?(key)
return object[key]
elsif object.is_a? Enumerable
object.find { |*a| found = deep_find(key, a.last) }
return found
end
end
end
Hash.deep_find(key)