Создание глубокого вложенного хэша с использованием циклов в Ruby - PullRequest
0 голосов
/ 22 мая 2019

Я хочу создать вложенный хэш, используя четыре значения type, name, year, value.т. е. ключ первого хэша будет 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"
        }
    }
}

Я опробовал некоторые методы, но, похоже, они не работают так, как ожидалось.Как я могу это сделать?

Ответы [ 2 ]

4 голосов
/ 22 мая 2019
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) } для определения значений ключей, присутствующих в обоих объединяемых хэшах. См. Документ для определения трех переменных блока (здесь _, o и n). Обратите внимание, что при выполнении o.merge(n) o и n не будет общих ключей, поэтому блок для этого не требуется работа.

2 голосов
/ 22 мая 2019

Предполагая, что вы хотите сохранить ссылки (в отличие от желаемого результата), вы идете:

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"}}}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...