arr = [
{ type: 1, price: 50, discounted_price: 40 },
{ type: 2, price: 150, discounted_price: 140 },
{ type: 1, price: 40, discounted_price: 30 },
{ type: 2, price: 140, discounted_price: 130 }
]
arr.each_with_object({}) do |g,h|
h.update(g[:type]=>g) do |_,o,n|
{ type: o[:type], price: o[:price]+n[:price],
discounted_price: o[:discounted_price] + n[:discounted_price] }
end
end.values
#=> [{:type=>1, :price=>90, :discounted_price=>70},
# {:type=>2, :price=>290, :discounted_price=>270}]
Обратите внимание, что получатель values
равен
{1=>{:type=>1, :price=> 90, :discounted_price=> 70},
2=>{:type=>2, :price=>290, :discounted_price=>270}}
Используется форма Hash # update (он же merge!
), в котором используется блок
do |_,o,n|
{ type: o[:type], price: o[:price]+n[:price],
discounted_price: o[:discounted_price] + n[:discounted_price] }
end
для определения значений ключей, которые присутствуют в обоих объединяемых хешах. См. Документацию для определения трех блочных переменных, _
, o
и n
.
Обычной практикой является использование подчеркивания для любой переменной блока, которая не используется в расчете блока, главным образом для информирования читателя. Здесь первая блочная переменная содержит общий ключ. (Некоторые могут использовать _k
для этой блочной переменной.)
Hash#update
и Enumerable # group_by тесно связаны в том смысле, что (как здесь), где один может использоваться, другой, вероятно, мог бы использоваться вместо этого. Выбор между ними, как правило, является стилистическим предпочтением.