2016-03-07 139 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)