MS-87
MS-87

Reputation: 193

Adding all relevant elements in array by a given element

I'm for some reason hitting a wall here. I need help figuring this out please. I have the following type of 2D array:

[["Bob", "Car", 25000],
["Bob", "TV", 5000],
["Bob", "dog", 1000],
["Sue", "Cat", 1000],
["Sue", "Car", 10000],
["Bob", "shoes", 100],
["Carol", "car", 20000]]

And I need to generate an array that is the sum of each of these people's total from the third element of each sub array. ie:

[["Bob", 31100],
["Sue", 11000],
["Carol", 20000]]

Right now I have a complicated and contrived solution using two loops that iterate through the entire array for each of its own elements. Is there an easier more streamlined way to do this? Especially since my data sets will be quite large. I know ruby has a bunch of awesome enumerables that seem like would fit here, but I can't quite think of how to fit them in.

Upvotes: 2

Views: 53

Answers (4)

Nakilon
Nakilon

Reputation: 35064

.group_by(&:first).map do |who, group|
  [who, group.map(&:last).inject(:+)]
end

Upvotes: 1

Cary Swoveland
Cary Swoveland

Reputation: 110675

You can use a counting hash:

arr = [["Bob", "Car", 25000],
       ["Bob", "TV", 5000],
       ["Bob", "dog", 1000],
       ["Sue", "Cat", 1000],
       ["Sue", "Car", 10000],
       ["Bob", "shoes", 100],
       ["Carol", "car", 20000]]

arr.each_with_object(Hash.new(0)) { |(name,_,total),h| h[name] += total }
  #=> {"Bob"=>31100, "Sue"=>11000, "Carol"=>20000}

Hash::new is used to create a hash with a default value of zero. That means that if the hash h does not have a key name, h[name] returns zero. Since:

h[name] += total

expands to:

h[name] = h[name] + total

h[name] on the right side of the equality returns zero when h does not have a key name.

Upvotes: 4

Hyung Cho
Hyung Cho

Reputation: 127

arr = [["Bob", "Car", 25000],
["Bob", "TV", 5000],
["Bob", "dog", 1000],
["Sue", "Cat", 1000],
["Sue", "Car", 10000],
["Bob", "shoes", 100],
["Carol", "car", 20000]]

hash_result = Hash.new(0)

arr.each do |record|
  hash_result[record[0]] += record[2]
end

This will give you a hash result. If you want an array, just call to_a on hash_result.

Upvotes: 1

Schwern
Schwern

Reputation: 164679

You can iterate through the array of purchases and store the totals in a hash.

purchases = [
  ["Bob", "Car", 25000],
  ["Bob", "TV", 5000],
  ["Bob", "dog", 1000],
  ["Sue", "Cat", 1000],
  ["Sue", "Car", 10000],
  ["Bob", "shoes", 100],
  ["Carol", "car", 20000]
]

totals = Hash.new(0)  # initialize the values to 0
purchases.each { |purchase|
  totals[purchase[0]] += purchase[2]
}

Upvotes: 1

Related Questions