Вот несколько способов сделать это, мои предпочтения быть первым.
Используйте подсчета хэш
код
def combine(data)
data.each_with_object(Hash.new(0)) { |(date, val), h| h[date] += val }.to_a
end
См Hash::new, обсуждение значения по умолчанию, в частности.
Пример
data = [['oct 1', 4], ['oct 2', 5], ['oct 3', 9], ['oct 1', 2]]
combine data
#=> [["oct 1", 6], ["oct 2", 5], ["oct 3", 9]]
Объяснения
enum = data.each_with_object(Hash.new(0))
#=> #<Enumerator: [["oct 1", 4], ["oct 2", 5], ["oct 3", 9],
# ["oct 1", 2]]:each_with_object({})>
Мы можем увидеть значение, генерируемое этого счетчику путем преобразования его в массив.
enum.to_a
#=> [[["oct 1", 4], {}], [["oct 2", 5], {}], [["oct 3", 9], {}],
# [["oct 1", 2], {}]]
Первое значение enum
передается в блок и значение блоков переменных вычисляются, используя устранения неоднозначности и параллельного назначение.
(date, val), h = enum.next
#=> [["oct 1", 4], {}]
date
#=> "oct 1"
val
#=> 4
h[date] += val
#=> h[date] = h[date] + val
#=> h["oct 1"] = h["oct 1"] + 4
#=> h["oct 1"] = 0 + 4 (no key "oct 1" so default value of `0` used)
#=> h["oct 1"] = 4
Теперь
h #=> {"oct 1"=>4}
Остальные три значения enum
передаются в блок и блок вычисления выполняются.
(date, val), h = enum.next
#=> [["oct 2", 5], {"oct 1"=>4}]
h[date] += val
#=> 5 (the default value of `0` is again used)
h #=> {"oct 1"=>4, "oct 2"=>5}
(date, val), h = enum.next
#=> [["oct 3", 9], {"oct 1"=>4, "oct 2"=>5}]
h[date] += val
#=> 9 (the default value of `0` is again used)
h #=> {"oct 1"=>4, "oct 2"=>5, "oct 3"=>9}
(date, val), h = enum.next
#=> [["oct 1", 2], {"oct 1"=>4, "oct 2"=>5, "oct 3"=>9}]
h[date] += val
#=> 6
h #=> {"oct 1"=>6, "oct 2"=>5, "oct 3"=>9}
В последнем вычислении значение по умолчанию не используется, потому что хэш h
уже имел ключ "oct 1"
:
h[date] += val
#=> h[date] = h[date] + val
#=> h["oct 1"] = h["oct 1"] + 2
#=> h["oct 1"] = 4 + 2
Наконец,
h.to_a
#=> [["oct 1", 6], ["oct 2", 5], ["oct 3", 9]]
Использование Enumerable#group_by
Код
def combine(data)
data.group_by(&:first).map { |date, vals| [date, vals.map(&:last).reduce(:+)] }
end
Пример
combine data
#=> [["oct 1", 6], ["oct 2", 5], ["oct 3", 9]]
Пояснение
шаги:
h = data.group_by(&:first)
#=> {"oct 1"=>[["oct 1", 4], ["oct 1", 2]],
# "oct 2"=>[["oct 2", 5]], "oct 3"=>[["oct 3", 9]]}
Th E первый ключ-значение пара h
передается к блоку:
date, vals = h.first
#=> ["oct 1", [["oct 1", 4], ["oct 1", 2]]]
date
#=> "oct 1"
vals
#=> [["oct 1", 4], ["oct 1", 2]]
и расчет блока выполняется.
a = vals.map(&:last)
#=> [4, 2]
t = a.reduce(:+)
#=> 6
Таким образом, первый ключ-значение пары h
сопоставляется
[date, t]
#=> ["oct 1", 6]
Остальные расчеты аналогичны.
Мы хотели бы видеть вашу попытку решить эту проблему. Без этих доказательств усилий похоже, что вы хотите, чтобы мы выполнили работу, которую вы должны были сделать. Пожалуйста, прочитайте «[ask]», «[mcve]» и «[Сколько ожидаемых усилий для пользователей Stack Overflow?] (Http://meta.stackoverflow.com/a/261593/128421)». –