【问题标题】:what's the best way to convert a ruby hash to an array将红宝石哈希转换为数组的最佳方法是什么
【发布时间】:2010-10-19 21:03:26
【问题描述】:

我有一个像这样的 ruby​​ 哈希

{ "stuff_attributes" => {
     "1" => {"foo" => "bar", "baz" => "quux"}, 
     "2" => {"foo" => "bar", "baz" => "quux"} 
   }
}

我想把它变成一个像这样的哈希

{ "stuff_attributes" => [
    { "foo" => "bar", "baz" => "quux"},
    { "foo" => "bar", "baz" => "quux"}
  ]
}

我还需要保留键的数字顺序,并且键的数量是可变的。上面是超级简化的,但我在底部包含了一个真实的例子。最好的方法是什么?

附言

也需要递归

就递归而言,这是我们可以假设的:

1) 需要操作的key会匹配/_attributes$/ 2) 哈希会有很多其他不匹配的键 /_attributes$/ 3)散列中的键总是一个数字 4) _attributes 哈希可以在任何其他键下的任何级别的哈希

这个散列实际上是控制器中创建操作的参数散列。这是需要使用此例程解析的真实示例。

{
    "commit"=>"Save", 
    "tdsheet"=>{
    "team_id"=>"43", 
    "title"=>"", 
    "performing_org_id"=>"10", 
    "tdsinitneed_attributes"=>{ 
        "0"=>{
            "title"=>"", 
            "need_date"=>"", 
            "description"=>"", 
            "expected_providing_organization_id"=>"41"
            }, 
        "1"=>{
            "title"=>"", 
            "need_date"=>"", 
            "description"=>"", 
            "expected_providing_organization_id"=>"41"
            }
        }, 
        "level_two_studycollection_id"=>"27", 
        "plan_attributes"=>{
            "0"=>{
                "start_date"=>"", "end_date"=>""
            }
        }, 
        "dataitem_attributes"=>{
            "0"=>{
                "title"=>"", 
                "description"=>"", 
                "plan_attributes"=>{
                    "0"=>{
                        "start_date"=>"", 
                        "end_date"=>""
                        }
                    }
                }, 
            "1"=>{
                "title"=>"", 
                "description"=>"", 
                "plan_attributes"=>{
                    "0"=>{
                        "start_date"=>"", 
                        "end_date"=>""
                        }
                    }
                }
            }
        }, 
    "action"=>"create", 
    "studycollection_level"=>"", 
    "controller"=>"tdsheets"
}

【问题讨论】:

    标签: ruby arrays hash


    【解决方案1】:

    请注意,在转换之前测试所有键是否都是数字可能会很长...

    def array_from_hash(h)
      return h unless h.is_a? Hash
    
      all_numbers = h.keys.all? { |k| k.to_i.to_s == k }
      if all_numbers
        h.keys.sort_by{ |k| k.to_i }.map{ |i| array_from_hash(h[i]) }
      else
        h.each do |k, v|
          h[k] = array_from_hash(v)
        end
      end
    end
    

    【讨论】:

    • NameError: 未定义的局部变量或方法key' for #<Object:0x841c99c> from /storage/cait/development/app/helpers/application_helper.rb:6:in array_from_hash'
    • 通过将 k.to_i.to_s == 键更改为 k.to_i.to_s == k 来修复该错误后,它可以正常工作!谢谢!
    • 你有一些有趣的想法wrt在这里缩进:)
    【解决方案2】:

    如果我们可以假设所有的键实际上都是可以干净地转换为整数的字符串,那么以下应该可以工作:

    # "hash" here refers to the main hash in your example, since you didn't name it
    stuff_hash = hash["stuff"]
    hash["stuff"] = stuff_hash.keys.sort_by {|key| key.to_i}.map {|key| stuff_hash[key]}
    

    【讨论】:

    • 我怎样才能递归地做到这一点?我忘了在问题中提到这一点:\
    • 您能否提供一个完整结构组合方式的示例?递归需要走多深,我们如何区分需要转换的哈希和不需要转换的哈希(例如内部的 {"foo" => "bar", "baz" => "quux" })?
    • 在问题底部添加了更多规则,谢谢帮助:)
    【解决方案3】:

    冒昧地说,我将发布一个与 Vincent Robert 非常相似的代码示例。

    这是用.to_array 方法修补Hash 类。

     class Hash
       def to_array(h = self)
         return h unless h.is_a? Hash
         if h.keys.all? { |k| k.to_i.to_s == k } # all keys are numbers so make an array.
           h.keys.sort_by{ |k| k.to_i }.map{ |i| self.to_array(h[i]) }
         else
           h.each do |k, v|
             h[k] = self.to_array(v)
           end
         end
       end
     end
    

    使用起来稍微方便一些。

    【讨论】:

      猜你喜欢
      • 2010-09-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-06-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多