如何通过相同的键组合数组中多个散列的值
How to combine the value of multiple hashes within an array by the same key
我有一个像这样的哈希数组:
[{"apple"=>5}, {"banana"=>4}, {"orange"=>6}, {"apple"=>4}, {"orange"=>2}]
我如何到达:
[{"apple"=>9}, {"banana"=>4}, {"orange"=>8}]
方法有很多种,您很快就会看到。这是一个:
arr = [{"apple"=>5}, {"banana"=>4}, {"orange"=>6}, {"apple"=>4}, {"orange"=>2}]
arr.flat_map(&:to_a)
.group_by(&:first)
.map { |k,a| { k=>(a.reduce(0) { |tot,(_,v)| tot+v }) } }
#=> [{"apple"=>9}, {"banana"=>4}, {"orange"=>8}]
步骤:
a = arr.flat_map(&:to_a)
#=> [["apple",5], ["banana",4], ["orange",6], ["apple",4], ["orange",2]]
b = a.group_by(&:first)
#=> {"apple"=>[["apple", 5], ["apple", 4]],
# "banana"=>[["banana", 4]],
# "orange"=>[["orange", 6], ["orange", 2]]}
b.map { |k,a| { k=>(a.reduce(0) { |tot,(_,v)| tot+v }) } }
#=> [{"apple"=>9}, {"banana"=>4}, {"orange"=>8}]
让我们仔细看看b.map
:
enum = b.map
#=> #<Enumerator: {
# "apple"=>[["apple", 5], ["apple", 4]],
# "banana"=>[["banana", 4]],
# "orange"=>[["orange", 6], ["orange", 2]]
# }:map>
enum
的第一个元素被传递(由Enumerator#each, which in turn calls Array#each) to the block and assigned to the block variables. We can simulate that using Enumerator#next:
k,a = enum.next
#=> ["apple", [["apple", 5], ["apple", 4]]]
k #=> "apple"
a #=> [["apple", 5], ["apple", 4]]
计算:
c = a.reduce(0) { |tot,(_,v)| tot+v }
#=> 9
将a
的第一个元素传递给块并赋值块变量:
tot, (_,v) = 0, ["apple", 5]
#=> [0, ["apple", 5]]
tot #=> 0
v #=> 5
然后我们计算:
tot + 5
#=> 0+5 => 5
被 return 编辑为 reduce
成为 tot
的更新值。传入第二个值a
:
tot, (_,v) = 5, ["apple", 4]
tot #=> 5
v #=> 4
我们计算 return:
tot+4
# 5+4 => 9
所以:
{ k=>tot }
#=> { "apple"=>9 }
是a
第一个元素的映射值。其余映射值的计算方式类似。
还有:
cache = Hash.new { |h, k| h[k] = { k => 0 } }
aoh.flat_map(&:to_a)
.each_with_object(cache) { |(k,v),h| h[k][k] += v }
.values
为了更清楚一点,或者在更多的片段中:
cache = Hash.new { |h, k| h[k] = { k => 0 } }
sum = -> ((k, v), h) { h[k][k] += v }
summary = aoh.flat_map(&:to_a)
.each_with_object(cache, &sum)
.values
看起来有些奇怪的 cache
哈希同时做两件事:
- 跟踪到目前为止在其密钥中看到了哪些密钥。
- 在其值中跟踪我们想要的最终结果。
我有一个像这样的哈希数组:
[{"apple"=>5}, {"banana"=>4}, {"orange"=>6}, {"apple"=>4}, {"orange"=>2}]
我如何到达:
[{"apple"=>9}, {"banana"=>4}, {"orange"=>8}]
方法有很多种,您很快就会看到。这是一个:
arr = [{"apple"=>5}, {"banana"=>4}, {"orange"=>6}, {"apple"=>4}, {"orange"=>2}]
arr.flat_map(&:to_a)
.group_by(&:first)
.map { |k,a| { k=>(a.reduce(0) { |tot,(_,v)| tot+v }) } }
#=> [{"apple"=>9}, {"banana"=>4}, {"orange"=>8}]
步骤:
a = arr.flat_map(&:to_a)
#=> [["apple",5], ["banana",4], ["orange",6], ["apple",4], ["orange",2]]
b = a.group_by(&:first)
#=> {"apple"=>[["apple", 5], ["apple", 4]],
# "banana"=>[["banana", 4]],
# "orange"=>[["orange", 6], ["orange", 2]]}
b.map { |k,a| { k=>(a.reduce(0) { |tot,(_,v)| tot+v }) } }
#=> [{"apple"=>9}, {"banana"=>4}, {"orange"=>8}]
让我们仔细看看b.map
:
enum = b.map
#=> #<Enumerator: {
# "apple"=>[["apple", 5], ["apple", 4]],
# "banana"=>[["banana", 4]],
# "orange"=>[["orange", 6], ["orange", 2]]
# }:map>
enum
的第一个元素被传递(由Enumerator#each, which in turn calls Array#each) to the block and assigned to the block variables. We can simulate that using Enumerator#next:
k,a = enum.next
#=> ["apple", [["apple", 5], ["apple", 4]]]
k #=> "apple"
a #=> [["apple", 5], ["apple", 4]]
计算:
c = a.reduce(0) { |tot,(_,v)| tot+v }
#=> 9
将a
的第一个元素传递给块并赋值块变量:
tot, (_,v) = 0, ["apple", 5]
#=> [0, ["apple", 5]]
tot #=> 0
v #=> 5
然后我们计算:
tot + 5
#=> 0+5 => 5
被 return 编辑为 reduce
成为 tot
的更新值。传入第二个值a
:
tot, (_,v) = 5, ["apple", 4]
tot #=> 5
v #=> 4
我们计算 return:
tot+4
# 5+4 => 9
所以:
{ k=>tot }
#=> { "apple"=>9 }
是a
第一个元素的映射值。其余映射值的计算方式类似。
还有:
cache = Hash.new { |h, k| h[k] = { k => 0 } }
aoh.flat_map(&:to_a)
.each_with_object(cache) { |(k,v),h| h[k][k] += v }
.values
为了更清楚一点,或者在更多的片段中:
cache = Hash.new { |h, k| h[k] = { k => 0 } }
sum = -> ((k, v), h) { h[k][k] += v }
summary = aoh.flat_map(&:to_a)
.each_with_object(cache, &sum)
.values
看起来有些奇怪的 cache
哈希同时做两件事:
- 跟踪到目前为止在其密钥中看到了哪些密钥。
- 在其值中跟踪我们想要的最终结果。