Как суммировать значения одинаковых ключей в массиве одного типа? - PullRequest
0 голосов
/ 25 апреля 2019

у меня есть массив input

[
  { 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 }
]

и какой ожидаемый результат:

[
  { 
     type: 1, 
     price: 90, # =>  50 + 40
     discounted_price: 70 # =>  40 + 30
  },
  {
     type: 2,
     price: 290, # => 150 + 140
     discounted_price: 270 # => 140 + 130
  }
]

Я уже пробовал reduce и group_by методы, но не могу понять.

https://medium.com/@james.a.hughes/using-the-reduce-method-in-ruby-907f3c18ae1f

input.group_by { |item| 
  [item[:type]] 
}.values.flat_map { |items| 
  items.first.merge(price: items.sum { |h| h[:price].to_f }) 
}

это сумма цены, но я хочу и цену, и цену со скидкой.

Ответы [ 2 ]

2 голосов
/ 25 апреля 2019
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 тесно связаны в том смысле, что (как здесь), где один может использоваться, другой, вероятно, мог бы использоваться вместо этого. Выбор между ними, как правило, является стилистическим предпочтением.

2 голосов
/ 25 апреля 2019

Вы можете использовать group_by и reduce:

input.group_by { |item| item[:type] }.map do |_, collection|
  collection.reduce do |result, item| 
    result[:price] += item[:price]
    result[:discounted_price] += item[:discounted_price]
    result
  end
end

Но достаточно использовать и reduce:

input.reduce([]) do |result, item|
  result_i = result.find { |result_i| result_i[:type] == item[:type] }

  if result_i
    result_i[:price] += item[:price]
    result_i[:discounted_price] += item[:discounted_price]
    result
  else
    result << item 
  end
end
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...