user2320239
user2320239

Reputation: 1038

Array to hash while summing values

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

Answers (4)

Oleksandr Holubenko
Oleksandr Holubenko

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

Stefan
Stefan

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

axiac
axiac

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

Surya
Surya

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

Related Questions