Reputation: 1437
So I know how to add all the values in an array.
Example, the sum of [1,2,3,4]...
[1,2,3,4].inject(&:+)
#=> 10
However, I have an array of arrays and would like to add the values that have the same first element of each sub array.
# example
[["A", 10],["A", 5],["B", 5],["B", 5],["C", 15], ["C", 15]]
"(A : 15) - (B : 10) - (C : 30)"
Any help would be appreciated!
Upvotes: 2
Views: 1218
Reputation: 580
There are more elegant ways of doing this, but here is the solution as a block, so you can understand the logic...
What this does is :
'
my_array = [["A", 10],["A", 5],["B", 5],["B", 5],["C", 15],["C", 15]]
my_hash = {}
output_array = []
my_array.each do |item|
my_hash[item[0]] ||= 0
my_hash[item[0]] += item[1]
end
my_hash.each do |k,v|
output_array.push("(#{k} : #{v})")
end
puts output_array.join(" - ")
Upvotes: 0
Reputation: 52357
a = [["A", 10],["A", 5],["B", 5],["B", 5],["C", 15], ["C", 15]]
result = a.group_by(&:first).each_with_object({}) do |(k, v), h|
h[k] = v.map(&:last).inject(:+)
# if your on Ruby 2.4+ you can write h[k] = v.sum(&:last)
end
#=> {"A"=>15, "B"=>10, "C"=>30}
Another option would be to build the hash from the beginning:
result = a.each_with_object({}) {|(k, v), h| h[k] = h[k].to_i + v }
#=> {"A"=>15, "B"=>10, "C"=>30}
If your desired output is literally a string "(A : 15) - (B : 10) - (C : 30)"
:
result.map { |k, v| "(#{k} : #{v})" }.join(' - ')
#=> "(A : 15) - (B : 10) - (C : 30)"
Upvotes: 2
Reputation: 27793
Try this
arr = [["A", 10],["A", 5],["B", 5],["B", 5],["C", 15], ["C", 15]]
arr.group_by(&:first).map { |key, group| [key, group.map(&:last).inject(:+)] }
# => [["A", 15], ["B", 10], ["C", 30]]
How does this work?
group_by(&:first)
groups the subarrays by first elementmap { |key, group| ... }
transforms the groupsgroup.map(&:last).inject(:+)
sums up all last elements in a groupUpvotes: 2
Reputation: 110675
arr = [["A", 10],["A", 5],["B", 5],["B", 5],["C", 15], ["C", 15]]
h = arr.each_with_object(Hash.new(0)) { |(f,g),h| h[f] += g }
#=> {"A"=>15, "B"=>10, "C"=>30}
Then
h.map { |pair| "(%s : %s)" % pair }.join(" - ")
#=> "(A : 15) - (B : 10) - (C : 30)"
which you can combine like so:
arr.each_with_object(Hash.new(0)) { |(f,g),h| h[f] += g }.
map { |pair| "(%s : %s)" % pair }.join(" - ")
See Hash::new, especially with regards to the use of a default value (here 0
).
Upvotes: 3