Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Ruby Multidimensional Array - Remove duplicate in first position, add number in second position

Tags:

arrays

ruby

For this array:

items = [[60, 3], [60, 3], [276, 2], [276, 2], [48, 2], [207, 2], [46, 2],
 [60, 2], [280, 2], [207, 1], [48, 1], [112, 1], [60, 1], [207, 1], [112, 1],
 [276, 1], [48, 1], [276, 1], [48, 1], [276, 1], [276, 1], [278, 1], [46, 1],
 [48, 1], [279, 1], [207, 1]]

I want to combine common numbers in the first positions of each sub-array, and add the numbers in the second positions together.

For instance, you'll see the first four sub-arrays here are: [60, 3], [60, 3], [276, 2], [276, 2]

This would become: [60,6], [276,4] and so on.

like image 404
Goldnuggets Avatar asked Nov 28 '22 02:11

Goldnuggets


2 Answers

Try this

items.
  group_by {|i| i[0]}.
  map{|key, value| [key,value.inject(0){|sum, x| sum + x[1]}]}

Firstly, use group_by to create a hash whose keys is the first element of each array. So we have

{
 60=>[[60, 3], [60, 3], [60, 2], [60, 1]],
 276=>[[276, 2], [276, 2], [276, 1], [276, 1], [276, 1], [276, 1]],
 48=>[[48, 2], [48, 1], [48, 1], [48, 1], [48, 1]],
 207=>[[207, 2], [207, 1], [207, 1], [207, 1]],
 46=>[[46, 2], [46, 1]],
 280=>[[280, 2]],
 112=>[[112, 1], [112, 1]],
 278=>[[278, 1]],
 279=>[[279, 1]]
}

Then to create the desired result, using map method to loop the hash. To calculate total value for each key, using inject method to sum all second value of each array

[[60, 3], [60, 3], [60, 2], [60, 1]].inject(0) {|sum, x| sum + x[1]} #value is 9
like image 125
Long Nguyen Avatar answered Dec 19 '22 08:12

Long Nguyen


You could use Enumerable#each_with_object

Iterates the given block for each element with an arbitrary object given, and returns the initially given object.

items.each_with_object(Hash.new(0)) {|a, h| h[a[0]] += a[1]}.to_a
# => [[60, 9], [276, 8], [48, 6], [207, 5], [46, 3], [280, 2],
#     [112, 2], [278, 1], [279, 1]]

From Stefen's comment

The Array passed to the block can be decomposed like this

items.each_with_object(Hash.new(0)) {|(k,v), h| h[k] += v}.to_a
like image 27
Santhosh Avatar answered Dec 19 '22 09:12

Santhosh