【问题标题】:Create a deep nested hash using loops in Ruby在 Ruby 中使用循环创建深层嵌套哈希
【发布时间】:2019-05-22 06:12:48
【问题描述】:

我想使用四个值 typenameyearvalue 创建一个嵌套哈希。即,第一个散列的键是type,值是另一个散列,键是name,然后那个值是另一个散列,键是year,值是value

我正在迭代的对象数组如下所示:

elements = [
    {
        year: '2018',
        items: [
            {
                name: 'name1',
                value: 'value1',
                type: 'type1',
            },
            {
                name: 'name2',
                value: 'value2',
                type: 'type2',
            },
        ]
    },
    {
        year: '2019',
        items: [
            {
                name: 'name3',
                value: 'value3',
                type: 'type2',
            },
            {
                name: 'name4',
                value: 'value4',
                type: 'type1',
            },
        ]
    }
]

我正在使用这样的两个循环将所有值放在一起:

elements.each do |element|
    year = element.year
    element.items.each |item|
        name = item.name
        value = item.value
        type = item.type

        # TODO: create nested hash
    end
end

预期的输出是这样的:

{
    "type1" => {
        "name1" => {
            "2018" => "value1"
        },
        "name4" => {
            "2019" => "value4"
        }
    },
    "type2" => {
        "name2" => {
            "2018" => "value2"
        },
        "name3" => {
            "2019" => "value3"
        }
    }
}

我尝试了一些方法,但似乎没有达到预期的效果。我该怎么做?

【问题讨论】:

  • 能否添加您尝试过的解决方案
  • 您的 JSON 格式错误。
  • @AlekseiMatiushkin 实际上它是一个对象数组,只是更正了它

标签: ruby-on-rails ruby


【解决方案1】:
elements.each_with_object({}) { |g,h| g[:items].each { |f|
    h.update(f[:type]=>{ f[:name]=>{ g[:year]=>f[:value] } }) { |_,o,n| o.merge(n) } } }
  #=> {"type1"=>{"name1"=>{"2018"=>"value1"}, "name4"=>{"2019"=>"value4"}},
  #    "type2"=>{"name2"=>{"2018"=>"value2"}, "name3"=>{"2019"=>"value3"}}} 

这使用Hash#update(又名merge!)的形式,它使用一个块(这里{ |_,o,n| o.merge(n) } 来确定两个哈希中存在的键的值被合并。有关三个块的定义,请参见文档变量(此处为 _on)。请注意,在执行 o.merge(n) 时,on 将没有公共键,因此该操作不需要块。

【讨论】:

  • 好一个!我想知道我们什么时候会有Hash#bury 或者想避开这个丑陋的栅栏{=>{=>{=>{=> :)
  • @AlekseiMatiushkin: class Hash; def bury(*keys, val); keys.size > 1 ? self.dig(*keys[0..-2])[keys[-1]] = val : self[keys.first] = val; end; end(不过,哈希最好是自动激活的,否则它不会太有用),
【解决方案2】:

假设您想要保留引用(与您想要的输出不同),您可以这样做:

elements = [
  {
    year: '2018',
    items: [
      {name: 'name1', value: 'value1', type: 'type1'},
      {name: 'name2', value: 'value2', type: 'type2'}
    ]
},
{
    year: '2019',
    items: [
      {name: 'name3', value: 'value3', type: 'type2'},
      {name: 'name4', value: 'value4', type: 'type1'}
    ]
  }
]

只需遍历所有内容并归约到哈希中。关于已知形状的结构是一项微不足道的任务:

elements.each_with_object(
    Hash.new { |h, k| h[k] = Hash.new(&h.default_proc) } # for deep bury
) do |h, acc|
  h[:items].each do |item|
    acc[item[:type]][item[:name]][h[:year]] = item[:value]
  end
end

#⇒ {"type1"=>{"name1"=>{"2018"=>"value1"},
#             "name4"=>{"2019"=>"value4"}},
#   "type2"=>{"name2"=>{"2018"=>"value2"},
#             "name3"=>{"2019"=>"value3"}}}

【讨论】:

    猜你喜欢
    • 2022-12-11
    • 2014-12-06
    • 2021-02-03
    • 2018-08-24
    • 2015-08-25
    • 2020-07-02
    • 2018-10-27
    • 2021-04-28
    • 2016-10-31
    相关资源
    最近更新 更多