How to find some arrays with certain value and sum their values?

I have an array of arrays with a lot of value. Where always the first and third element is repeated and I need to sum only the second element, because this is a number that I want totalizing.

Then make a new array with all values totalizing.

Example

# My array

=> [ ['abc', 13, 40 ], [ 'abc', 20, 40 ], [ 'abc', 2, 40 ], [ 'cde', 90, 20 ], [ 'cde', 60, 20 ], [ 'fgh', 20, 50 ] ]

# My Expected Result

=> [ ['abc', 35, 40 ], ['cde', 150, 20], ['fgh', 20, 50] ]

What would be the optimal way to do that? What functions could be used to reach that result?

Upvotes: 0

Views: 53

Answers (2)

bluexuemei
bluexuemei

Reputation: 233

arr.group_by { |a,_,c| [a,c] }.values.map{|x|[x[0][0],x.map{|n|n[1]}.reduce(&:+),x[0][2]]}

Upvotes: 0

Cary Swoveland
Cary Swoveland

Reputation: 110675

You can do that like this:

arr = [[ 'abc', 13, 40 ], [ 'abc', 20, 40 ], [ 'abc',  2, 40 ],
       [ 'cde', 90, 20 ], [ 'cde', 60, 20 ], [ 'fgh', 20, 50 ] ]

arr.group_by { |a,_,c| [a,c] }
   .map { |(a,b),arr| [a,arr.reduce(0) { |t,(_,e,_)| t + e },b] }
  #=> [["abc",  35, 40],
  #    ["cde", 150, 20],
  #    ["fgh",  20, 50]]

This is how this works:

f = arr.group_by { |a,_,c| [a,c] }
  #=> {["abc", 40]=>[["abc", 13, 40], ["abc", 20, 40], ["abc", 2, 40]],
  #    ["cde", 20]=>[["cde", 90, 20], ["cde", 60, 20]],
  #    ["fgh", 50]=>[["fgh", 20, 50]]}

map passes the first key-value pair of the hash f into its block, assigning the block variables (using decomposition) as follows:

a,b = ["abc", 40]
arr = [["abc", 13, 40], ["abc", 20, 40], ["abc", 2, 40]]

and then computes:

[a,g,b]
#=> ["abc", g, 40]

where

g = arr.reduce(0) { |t,(_,e,_)| t + e }
  #=> 35

so

["abc", 40]=>[["abc", 13, 40], ["abc", 20, 40], ["abc", 2, 40]]

is mapped to:

["abc", 35, 40]

The two other elements of the hash f are computed similarly.

Upvotes: 1

Related Questions