How to group elements of sub-arrays based on two elements

I have an input as follows:

input = [
  ["account1",10,"Dr"],
  ["account1",20,"Dr"],
  ["account2",15,"Cr"],
  ["account1",25,"Cr"],
  ["account2",10,"Dr"],
  ["account1",10,"Cr"]
]

I am trying to get the sums by account and transaction type, i.e., Dr or Cr. I need an output as below:

output = {
  ["account1","Dr"] => 30,
  ["account1","Cr"] => 35,
  ["account2","Dr"] => 10,
  ["account2","Cr"] => 15
}

I can sum the amount based on only account using:

input.each_with_object(Hash.new(0)) {|(f,g), h| h[f] += g}
# => {"account1"=>65, "account2"=>25}

Upvotes: 0

Views: 94

Answers (3)

Cary Swoveland
Cary Swoveland

Reputation: 110675

input.group_by { |acc,_,title| [acc, title] }.
      transform_values { |v| v.sum { |a| a[1] } }
  #=> {["account1", "Dr"]=>30, ["account2", "Cr"]=>15, ["account1", "Cr"]=>35,
  #    ["account2", "Dr"]=>10}

The first step is the following.

input.group_by { |acc,_,title| [acc, title] }
  #=> {
  #    ["account1", "Dr"]=>[["account1", 10, "Dr"], ["account1", 20, "Dr"]],
  #    ["account2", "Cr"]=>[["account2", 15, "Cr"]],
  #    ["account1", "Cr"]=>[["account1", 25, "Cr"], ["account1", 10, "Cr"]],
  #    ["account2", "Dr"]=>[["account2", 10, "Dr"]]
  #   }

Upvotes: 2

andriy-baran
andriy-baran

Reputation: 739

You can do so:

input.each_with_object(Hash.new(0)) {|(f,g,i), h| h[[f,i]] += g}

=> {["account1", "Dr"]=>30, ["account2", "Cr"]=>15, ["account1", "Cr"]=>35, ["account2", "Dr"]=>10}

Upvotes: 4

halfelf
halfelf

Reputation: 10107

output = Hash.new(0)  # set a default value of zero, avoiding nil
input.each do |account, amount, transaction|
    output[[account, transaction]] += amount
end

output #  {["account1", "Dr"]=>30, ["account2", "Cr"]=>15, ["account1", "Cr"]=>35, ["account2", "Dr"]=>10}

Upvotes: 1

Related Questions