2016-01-18 50 views
0
嵌套哈希

我想從這個哈希建立new_hash:迭代通過使用條件語句中的Ruby

languages = { 
    :oo => { 
    :ruby => { 
     :type => "interpreted" 
    }, 
    :javascript => { 
     :type => "interpreted" 
    }, 
    :python => { 
     :type => "interpreted" 
    } 
    }, 
    :functional => { 
    :clojure => { 
     :type => "compiled" 
    }, 
    :erlang => { 
     :type => "compiled" 
    }, 
    :javascript => { 
     :type => "interpreted" 
    } 
    } 
} 

和期望的結果是:

{ 
    :ruby => { 
    :type => "interpreted", 
    :style => [:oo] 
    }, 
    :javascript => { 
    :type => "interpreted", 
    :style => [:oo, :functional] 
    }, 
    :python => { 
    :type => "interpreted", 
    :style => [:oo] 
    }, 
    :clojure => { 
    :type => "compiled", 
    :style => [:functional] 
    }, 
    :erlang => { 
    :type => "compiled", 
    :style => [:functional] 
    } 
} 

這裏是我做了什麼等等遠:

def reformat_languages(languages) 
    new_hash = {} 
    languages.each do |k, v| 
    v.each do |k1, v1| 
     new_hash[k1] = v1 
     new_hash[k1][:style] = [] 
     new_hash[k1][:style] << k  
    end 
    end 
    new_hash 
end 

不幸的是,我無法得到想要的結果。據我所知,當迭代到達第二JavaScript的關鍵,它重新寫在第一次迭代給我:的

:javascript => { 
    :type => "interpreted", 
    :style => [:functional] 
    } 

代替:

:javascript => { 
    :type => "interpreted", 
    :style => [:oo, :functional] 
    } 

這裏是一個repl.it的鏈接在那裏我可以看到代碼在行動:https://repl.it/BebC

我知道我需要使用條件,但我不確定在哪裏以及使用它。如果有人能夠幫助我獲得理想的結果,並解釋一下爲什麼它的工作方式如此。

回答

1

您可以使用類似

h = {} 
languages.each do |k, v| # oo or func 
    v.each do |k1, v1| # ruby/python 
     if h[k1] 
      h[k1][:style] << k 
     else 
      h[k1] = {type: v1[:type], style: [k]} 
     end 
    end 
end 

它檢查該h定義,如果是這樣,追加到它的陣列。否則它會定義整個散列,其中包含大小爲1的類型和樣式數組。

+1

也很好的命名在這裏會有很大的幫助,但他會及時瞭解到這一點。 :) –

1

你的代碼中有太多的無條件覆蓋正在進行。如果是這樣,而不是:

new_hash[k1] ||= {} # init to empty hash 
    new_hash[k1][:type] = v1[:type] 
    new_hash[k1][:style] ||= [] # make sure array exists 
    new_hash[k1][:style] << k 

而不是更換整個new_hash[k1]的,你應該改變它的各個部分。

0

這不是答案(所以請勿上傳)。相反,它是一個擴展的評論,可以幫助你理解@Martin所建議的代碼。 (我發現你對SO很陌生,很可能也是對Ruby。)正如我所做的那樣,使用puts語句對代碼進行醃製通常是非常有用的,即使在您熟悉該語言之後也是如此。

languages = { 
    :oo => { 
    :ruby => { 
     :type => "interpreted" 
    }, 
    :javascript => { 
     :type => "interpreted" 
    } 
    }, 
    :functional => { 
    :clojure => { 
     :type => "compiled" 
    }, 
    :javascript => { 
     :type => "interpreted" 
    } 
    } 
} 

h = {} 
languages.each do |k, v| # oo or func 
    puts "k=#{k}, v=#{v}" 
    v.each do |k1, v1| # ruby/python 
    puts " k1=#{k1}, v1=#{v1}" 
    if h[k1] 
     puts " h[#{k1}]=#{h[k1]} (truthy)" 
     h[k1][:style] << k 
     puts " h after h[#{k1}][:style] << #{k}: #{h}" 
    else 
     puts " h[#{k1}].nil?=true (falsy)" 
     h[k1] = {type: v1[:type], style: [k]} 
     puts " h after h[#{k1}] = {type: v1[:type], style: #{k}}: #{h}" 
    end 
    end 
end 

打印:

k=oo, v={:ruby=>{:type=>"interpreted"}, :javascript=>{:type=>"interpreted"}} 

    k1=ruby, v1={:type=>"interpreted"} 
    h[ruby].nil?=true (falsy) 
    h after h[ruby] = {type: v1[:type], :style: oo}: 
    {:ruby=>{:type=>"interpreted", :style=>[:oo]}} 

    k1=javascript, v1={:type=>"interpreted"} 
    h[javascript].nil?=true (falsy) 
    h after h[javascript] = {type: v1[:type], :style: oo}: 
    {:ruby=>{:type=>"interpreted", :style=>[:oo]}, 
    :javascript=>{:type=>"interpreted", :style=>[:oo]}} 

k=functional, v={:clojure=>{:type=>"compiled"}, :javascript=>{:type=>"interpreted"}} 

    k1=clojure, v1={:type=>"compiled"} 
    h[clojure].nil?=true (falsy) 
    h after h[clojure] = {type: v1[:type], :style: functional}: 
    {:ruby=>{:type=>"interpreted", :style=>[:oo]}, 
    :javascript=>{:type=>"interpreted", :style=>[:oo]}, 
    :clojure=>{:type=>"compiled", :style=>[:functional]}} 

    k1=javascript, v1={:type=>"interpreted"} 
    h[javascript]={:type=>"interpreted", :style=>[:oo]} (truthy) 
    h after h[javascript][:style] << functional: 
    {:ruby=>{:type=>"interpreted", :style=>[:oo]}, 
    :javascript=>{:type=>"interpreted", :style=>[:oo, :functional]}, 
    :clojure=>{:type=>"compiled", :style=>[:functional]}} 

和回報:

#=> {:oo  =>{:ruby=>{:type=>"interpreted"}, 
    #     :javascript=>{:type=>"interpreted"}}, 
    # :functional=>{:clojure=>{:type=>"compiled"}, 
    #     :javascript=>{:type=>"interpreted"}}} 
+1

謝謝,卡里。這對我來說非常寶貴。 – gregmarquet

0

您將要覆蓋所產生的哈希值這是導致你所提到的意外行爲。以下代碼片段可以滿足您的需求。它只是你的代碼的一個稍微修改過的版本。

def reformat_languages(languages) 
    new_hash = {} 
    languages.each do |k, v| 
    v.each do |k1, v1| 
     new_hash[k1] ||= v1 #ensures we do not overwrite the already generated language hash 
     new_hash[k1][:style] ||= [] #protecting against re-initialization of the style array 
     new_hash[k1][:style] << k  
    end 
    end 
    new_hash 
end