Объединить ха sh массивов в массив хэшей - PullRequest
1 голос
/ 11 апреля 2020

Итак, у меня есть ха sh с массивами, как этот:

{"name": ["John","Jane","Chris","Mary"], "surname": ["Doe","Doe","Smith","Martins"]}

Я хочу объединить их в массив хэшей, объединяя соответствующие элементы.

Результаты должны быть такими:

[{"name"=>"John", "surname"=>"Doe"}, {"name"=>"Jane", "surname"=>"Doe"}, {"name"=>"Chris", "surname"=>"Smith"}, {"name"=>"Mary", "surname"=>"Martins"}] 

Есть идеи, как это сделать эффективно?


Обратите внимание, что сценарий реального использования может содержать переменное число га sh ключи.

Ответы [ 5 ]

2 голосов
/ 11 апреля 2020

Попробуйте это

h[:name].zip(h[:surname]).map do |name, surname|
  { 'name' => name, 'surname' => surname }
end
1 голос
/ 11 апреля 2020

Другой вариант для случая, когда:

[..] сценарий реального использования может содержать номер переменной га sh ключей

h = {
      'name': ['John','Jane','Chris','Mary'],
      'surname': ['Doe','Doe','Smith','Martins'],
      'whathever': [1, 2, 3, 4, 5]
    }

Вы можете использовать Object # затем с оператором splat в один слой:

h.values.then { |a, *b| a.zip *b }.map { |e| (h.keys.zip e).to_h }

#=> [{:name=>"John", :surname=>"Doe", :whathever=>1}, {:name=>"Jane", :surname=>"Doe", :whathever=>2}, {:name=>"Chris", :surname=>"Smith", :whathever=>3}, {:name=>"Mary", :surname=>"Martins", :whathever=>4}]

Первая часть , работает следующим образом:

h.values.then { |a, *b| a.zip *b }
#=> [["John", "Doe", 1], ["Jane", "Doe", 2], ["Chris", "Smith", 3], ["Mary", "Martins", 4]]

В последней части просто сопоставляются элементы, архивирующие каждый с оригинальными ключами, затем вызывается Array # to_h для преобразования в ha sh.

Здесь я убрал вызов .to_h, чтобы показать промежуточный результат:

h.values.then { |a, *b| a.zip *b }.map { |e| h.keys.zip e }
#=> [[[:name, "John"], [:surname, "Doe"], [:whathever, 1]], [[:name, "Jane"], [:surname, "Doe"], [:whathever, 2]], [[:name, "Chris"], [:surname, "Smith"], [:whathever, 3]], [[:name, "Mary"], [:surname, "Martins"], [:whathever, 4]]]
1 голос
/ 11 апреля 2020

Если ваш набор данных действительно большой, вы можете использовать Enumerator :: Lazy .

Таким образом Ruby не будет создавать промежуточные массивы во время вычислений.

Вот как можно улучшить ответ @ Ursus :

h[:name]
  .lazy
  .zip(h[:surname])
  .map { |name, surname| { 'name' => name, 'surname' => surname } }
  .to_a
1 голос
/ 11 апреля 2020
[h[:name], h[:surname]].transpose.map do |name, surname|
  { 'name' => name, 'surname' => surname }
end
1 голос
/ 11 апреля 2020

Я предлагаю написать код, разрешающий произвольное количество атрибутов. Это не сложнее, чем предполагать, что их два (:name и :surname), но обеспечивает большую гибкость, учитывая, например, будущие изменения количества или именования атрибутов:

def squish(h)
  keys = h.keys.map(&:to_s)
  h.values.transpose.map { |a| keys.zip(a).to_h }
end

h = { name:    ["John", "Jane", "Chris"],
      surname: ["Doe", "Doe", "Smith"],
      age:     [22, 34, 96]
    }    

squish(h)
  #=> [{"name"=>"John", "surname"=>"Doe", "age"=>22},
  #    {"name"=>"Jane", "surname"=>"Doe", "age"=>34},
  #    {"name"=>"Chris", "surname"=>"Smith", "age"=>96}] 

Шаги для приведенного выше примера следующие:

b = h.keys
  #=> [:name, :surname, :age] 
keys = b.map(&:to_s)
  #=> ["name", "surname", "age"] 
c = h.values
  #=> [["John", "Jane", "Chris"], ["Doe", "Doe", "Smith"], [22, 34, 96]] 
d = c.transpose
  #=> [["John", "Doe", 22], ["Jane", "Doe", 34], ["Chris", "Smith", 96]] 
d.map { |a| keys.zip(a).to_h }
  #=> [{"name"=>"John", "surname"=>"Doe", "age"=>22},
  #    {"name"=>"Jane", "surname"=>"Doe", "age"=>34},
  #    {"name"=>"Chris", "surname"=>"Smith", "age"=>96}] 

В последний шаг: первое значение b передается в блок map, а переменной блока присваивается его значение.

a = d.first
  #=> ["John", "Doe", 22] 
e = keys.zip(a)
  #=> [["name", "John"], ["surname", "Doe"], ["age", 22]] 
e.to_h
  #=> {"name"=>"John", "surname"=>"Doe", "age"=>22} 

Остальные вычисления аналогичны.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...