2016-03-07 76 views
2

我试图过滤嵌套散列并拉出各种键和值。下面是我在看的哈希:嵌套散列值访问值

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

欢迎SO。我们不在乎你的经验水平是什么,只是向我们展示你的研究成果,并且已经为解决问题付出了很大的努力,然后写出一个很好的问题。请不要使用称呼,说话或签名; SO不是论坛,它是一个问题和答案的参考书。 –

回答

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中的当前哈希值,并且由于没有其他东西被传入,value参数变成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}]] 

注意,零值都没有了。

重写你的代码考虑到这一点,再加上重构它简单:

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 

现在它回到你想要的钥匙,所以就很容易抓住整个哈希。 select是当你试图找到具体的事情要使用适当的方法:红宝石的

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}} 

旧版本并没有维持从哈希散列迭代器输出,所以我们不得不强制回哈希表:

e = exp.select { |k, v| v[:cty] == 'man' }.to_h 
# => {:spec=>{:cty=>"man", :ins=>2}, :aha=>{:cty=>"man", :ins=>0}} 
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 
0

作为锡文指出的那样,有两个参数可在通过散列迭代时传递到块(在这种情况下doend之间的代码)---一个用于其键和其他的价值。 要迭代虽然哈希(并打印出其值)使用.each方法

h = { a: "hello", b: "bonjour", c: "hola" } 

,你可以这样做:

h.each do |key, value| 
    puts value 
end 

结果将是:

hello 
bonjour 
hola 
=> {:a=>"hello", :b=>"bonjour", :c=>"hola"} 

请注意,值“返回”是我们迭代的散列值,其值在红宝石中为true。 (以外的任何其他nilfalse将评估在红宝石trueWhat 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(我现在正在这么做:)),这非常有用。

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)