【问题标题】:Turning a multi-dimensional array into a hash without overwriting values将多维数组转换为哈希而不覆盖值
【发布时间】:2015-09-15 09:00:04
【问题描述】:

我有一个多维数组如:

array = [["stop", "halt"],["stop", "red"],["go", "green"],["go","fast"],["caution","yellow"]]

我想把它变成这样的哈希:

hash = {"stop" => ["halt","red"], "go" => ["green","fast"], "caution" => "yellow"}

但是,当我 array.to_h 时,这些值会相互覆盖,我得到:

hash = {"stop" => "red", "go" => "fast", "caution" => "yellow"}

如何获得所需的数组?

【问题讨论】:

    标签: arrays ruby multidimensional-array hash


    【解决方案1】:

    这是一种方式。它使用Enumerable#each_with_objectHash#update(又名merge!)的形式,它使用一个块来确定在被合并的两个哈希中存在的键的值。

    array << ["stop", "or I'll fire!"]
    
    array.each_with_object({}) { |(f,l),h|
      h.update(f=>l) { |_,ov,nv| ov.is_a?(Array) ? ov << nv : [ov, nv] } }
      #=> {"stop"=>["halt", "red", "or I'll fire!"],
      #    "go"=>["green", "fast"],
      #    "caution"=>"yellow"}
    

    如果您希望返回的哈希中的所有值都是数组(即"caution"=&gt;["yellow"]),则代码被简化,这通常更方便后续计算:

    array.each_with_object({}) { |(f,l),h|  h.update(f=>[l]) {|_,ov,nv| ov+nv }}
      #=> {"stop"=>["halt", "red", "or I'll fire!"],
      #    "go"=>["green", "fast"],
      #    "caution"=>["yellow"]}
    

    【讨论】:

    • 谢谢你,卡里!我只有几周的时间开始编码(使用任何语言),所以我仍在努力熟悉许多方法和缩写。我一直在搜索文章以寻找对 each_with_object 的良好解释,但找不到任何真正让我清楚谈判的东西。你知道我在哪里可以找到一个好的解释吗?另外,是否有一种有效的方法来执行上述操作,但将所有值保留为数组?
    • Garrett,Enumerable#each_with_object 没有什么神秘之处,它在 1.9 版中首次亮相。假设a 是一个数组并且您希望这样做:b = []; a.each { |e| b &lt;&lt; e+1; b;即1.创建一个对象(b=[]); 2.对a的每个元素做一些事情; 3. 返回对象 (b)。这是一种非常常见的模式。 a.each_with_object([]) { |e,b| b &lt;&lt; e+1 } 允许您在一行而不是三行中做到这一点。不多也不少。将该方法想象为“each,带有一个对象”。我将编辑以解决您的其他问题。
    • 感谢您的解释和上面的附加代码!它增加了很多澄清。
    【解决方案2】:

    一种方法:

    array.inject({}) {|r, (k, v)| r[k] &&= [*r[k], v]; r[k] ||= v; r }
    

    虽然这很混乱。写出来,看起来是这样的:

    def to_hash_with_duplicates(arr)
      {}.tap do |r|
        arr.each do |k, v|
          r[k] &&= [*r[k], v]    # key already present, turn into array and add value
          r[k] ||= v             # key not present, simply store value
        end
      end
    end
    

    编辑:再想一想,@cary-swoveland 的 update-with-block 解决方案更好,因为它可以正确处理 nilfalse 值。

    【讨论】:

      猜你喜欢
      • 2019-07-14
      • 2016-05-08
      • 1970-01-01
      • 2019-10-27
      • 2019-05-23
      • 2012-10-29
      • 2011-01-16
      • 1970-01-01
      • 2020-01-26
      相关资源
      最近更新 更多