Reputation: 1038
I have a an array as follows:
[[172, 3],
[173, 1],
[174, 2],
[174, 3],
[174, 1]]
That I'd like to convert into an array, but while summing the values for matching keys. So I'd get the following:
{172 => 3, 173 => 1, 174 => 6}
How would I go about doing this?
Upvotes: 0
Views: 78
Reputation: 4440
You can try something about:
> array
#=> [[172, 3], [173, 1], [174, 2], [174, 3], [174, 1]]
array.group_by(&:first).map { |k, v| [k, v.map(&:last).inject(:+)] }.to_h
#=> => {172=>3, 173=>1, 174=>6}
Ruby 2.4.0 version:
a.group_by(&:first).transform_values { |e| e.sum(&:last) }
#=> => {172=>3, 173=>1, 174=>6}
Upvotes: 3
Reputation: 114158
How would I go about doing this?
Solve one problem at a time.
Given your array:
a = [[172, 3], [173, 1], [174, 2], [174, 3], [174, 1]]
We need an additional hash:
h = {}
Then we have to traverse the pairs in the array:
a.each do |k, v|
if h.key?(k) # If the hash already contains the key
h[k] += v # we add v to the existing value
else # otherwise
h[k] = v # we use v as the initial value
end
end
h #=> {172=>3, 173=>1, 174=>6}
Now let's refactor it. The conditional looks a bit cumbersome, what if we would just add everything?
h = {}
a.each { |k, v| h[k] += v }
#=> NoMethodError: undefined method `+' for nil:NilClass
Bummer, that doesn't work because the hash's values are initially nil
. Let's fix that:
h = Hash.new(0) # <- hash with default values of 0
a.each { |k, v| h[k] += v }
h #=> {172=>3, 173=>1, 174=>6}
That looks good. We can even get rid of the temporary variable by using each_with_object
:
a.each_with_object(Hash.new(0)) { |(k, v), h| h[k] += v }
#=> {172=>3, 173=>1, 174=>6}
Upvotes: 7
Reputation: 72216
Another possible solution:
arr = [[172, 3], [173, 1], [174, 2], [174, 3], [174, 1]]
hash = arr.each_with_object({}) {|a,h| h[a[0]] = h[a[0]].to_i + a[1]}
p hash
# {172=>3, 173=>1, 174=>6}
Upvotes: 1
Reputation: 15992
For:
array = [[172, 3], [173, 1], [174, 2], [174, 3], [174, 1]]
You could use a hash with a default value 0 like this
hash = Hash.new{|h,k| h[k] = 0 }
Then use it, and sum up values:
array.each { |a, b| hash[a] += b }
#=> {172=>3, 173=>1, 174=>6}
Upvotes: 1