0

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?

1
  • Welcome to Stack Overflow. Please read "How to Ask" and "minimal reproducible example" and the linked pages. The first thing is we need to see evidence of your effort. Without that it looks like you didn't try and want us to do it for you. Commented May 24, 2017 at 22:04

4 Answers 4

7

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}
Sign up to request clarification or add additional context in comments.

1 Comment

wow you even went through the parts that don't work to show the reasoning +1
3

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}

2 Comments

transform_values was introduced in 2.4? I must have overlooked it. Very useful! :-)
@Stefan yeap, in 2.4.0 :)
1

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}

Comments

1

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}

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.