Reputation: 511
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.
# 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
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
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