使用Ruby中的条件迭代嵌套哈希

时间:2016-01-18 05:31:42

标签: ruby hash

我正在尝试从这个哈希构建一个new_hash:

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

我知道我需要使用条件,但我不确定在哪里以及使用它。如果有人可以帮助我获得理想的结果并解释一下为什么它的工作方式有效。

4 个答案:

答案 0 :(得分: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],而不是替换整个events

答案 1 :(得分: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的样式数组定义整个哈希值。

答案 2 :(得分: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"}}} 

答案 3 :(得分: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