简体   繁体   English

如何通过相同的键组合数组中多个哈希的值

[英]How to combine the value of multiple hashes within an array by the same key

I have an array of hashes like so: 我有一系列的哈希像这样:

[{"apple"=>5}, {"banana"=>4}, {"orange"=>6}, {"apple"=>4}, {"orange"=>2}]

How I do get to: 我怎么做到:

[{"apple"=>9}, {"banana"=>4}, {"orange"=>8}]

There's also: 还有:

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

Or in more pieces to be a little clearer: 或者更多的部分更清楚一点:

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

The somewhat odd looking cache Hash does two things at once: 看起来有点奇怪的cache Hash同时做两件事:

  1. Keeps track of which keys have been seen so far in its keys. 跟踪其键中到目前为止看到的键。
  2. Keeps track of the final results we want in its values. 跟踪我们想要的最终结果。

There are many ways, as you will soon see. 你会很快看到很多方法。 Here's one: 这是一个:

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

The steps: 步骤:

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

Let's take a closer look at b.map : 让我们仔细看看b.map

enum = b.map
  #=> #<Enumerator: {
  #     "apple"=>[["apple", 5], ["apple", 4]],
  #     "banana"=>[["banana", 4]],
  #     "orange"=>[["orange", 6], ["orange", 2]]
  #   }:map> 

The first element of enum is passed (by Enumerator#each , which in turn calls Array#each ) to the block and assigned to the block variables. enum的第一个元素(通过Enumerator#each ,它又调用Array#each )传递给块并分配给块变量。 We can simulate that using Enumerator#next : 我们可以使用Enumerator#next来模拟它:

 k,a = enum.next
   #=> ["apple", [["apple", 5], ["apple", 4]]]
 k #=> "apple"
 a #=> [["apple", 5], ["apple", 4]]

To calculate: 计算:

 c = a.reduce(0) { |tot,(_,v)| tot+v }
   #=> 9

the first element of a is passed to the block and the block variables are assigned: 的第一个元素a被传递到块和块变量被分配:

 tot, (_,v) = 0, ["apple", 5]
     #=> [0, ["apple", 5]] 
 tot #=> 0
 v   #=> 5

We then compute: 然后我们计算:

 tot + 5
   #=> 0+5 => 5

which is returned to reduce to become the updated value of tot . 返回以reduce以成为tot的更新值。 The second value of a is passed in: 的第二值a传入:

 tot, (_,v) = 5, ["apple", 4]
 tot #=> 5
 v   #=> 4

and we calculate and return: 我们计算并返回:

 tot+4
   # 5+4 => 9

so: 所以:

 { k=>tot }
   #=> { "apple"=>9 }

is the mapped value of the first element of a . a的第一个元素的映射值。 The remaining mapped values are computed similarly. 其余映射值的计算方法类似。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM