所以说我有一个2D数组。也许是这样的:
data = [['oct 1', 4], ['oct 2', 5], ['oct 3', 9], ['oct 1', 2]]
我希望从中获取一个新数组,删除重复值(例如,oct 1),但总结相应的值。
所以我最终会:
data = (['oct 1', 6], ['oct 2', 5], ['oct 3', 9])
我可以想到一些方法来做到这一点,但它们看起来非常无穷无尽,而且通常会有一些疯狂的红宝石代码可以做几行代码,任何建议?
答案 0 :(得分:2)
以下是两种方法,我的偏好是第一种。
使用计算哈希
代码的
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]]
代码的
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]]}
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]
其余的计算方法类似。
答案 1 :(得分:1)
请尝试使用msg
方法:
inject