2

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.

1
  • 87, when you include an example in your question (a good thing), it's best to assign a variable to each input object. Here that might be arr = [['Bob', 'Car', 25000],...]. That way, readers can refer to arr in answers and comments without having to define it. Commented Oct 23, 2015 at 18:54

4 Answers 4

4

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.

Sign up to request clarification or add additional context in comments.

Comments

1
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.

2 Comments

each returns arr, so you need hash_result on a line by itself after the each block. I'll delete this comment when you've seen it, so no reply is req'd.
Thanks! This is a very simple and streamlined solution. Perfect
1

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

Comments

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.