1

Trying to add values of same key but with iterating it. here is my array

arr = [ {a: 10, b: 5, c: 2}, {a: 5, c: 3}, { b: 15, c: 4}, {a: 2}, {} ]

Want to converted it like

{a: 17, b: 20, c: 9} 

3 Answers 3

6

Here is one way to do this by making use of Enumerable#reduce and Hash#merge:

arr.reduce {|acc, h| acc.merge(h) {|_,v1,v2| v1 + v2 }}
#=> {:a=>17, :b=>20, :c=>9}
Sign up to request clarification or add additional context in comments.

5 Comments

(Hash.new {|h, k| 0}) can be omitted, but merge! should be replaced with merge (otherwise, arr[0] will be modified)
@falsetru Thanks for the tip - will update the answer
You can remove ({}) if you replace merge! with merge
@Stefan Thanks for that nice tip.
I think that is what @falsetru tried to suggest earlier. Note the parentheses in the comment ;-)
4

each_with_object to the rescue:

result = arr.each_with_object(Hash.new(0)) do |hash, result|
  hash.each { |key, value| result[key] += value}
end

p result

1 Comment

Thanks. I prefer each_with_object over reduce/inject (because it has a more logical order of the block parameters) and i think it is more readable than using merge. That being said: the merge solution is pretty sleek.
4

#1 Use a "counting hash"

Edit: I just noticed that @Pascal posted the same solution earlier. I'll leave mine for the explanation.

arr.each_with_object(Hash.new(0)) { |h,g| h.each { |k,v| g[k] += v } }
  #=> {:a=>17, :b=>20, :c=>9} 

h = Hash.new(0) is a counting hash with a default value of zero. That means that if h does not have a key k, h[k] returns zero (but the hash is not altered). Ruby expands h[k] += 4 to h[k] = h[k] + 4, so if h does not have a key k, h[k] on the right side of the equality equals zero.

#2 Use Hash#update

Specifically, use the form of this method (aka merge!) that employs a block to determine the values of keys that are present in both hashes being merged.

arr.each_with_object({}) { |h,g| g.update(h) { |_,o,n| o+n } }
  #=> {:a=>17, :b=>20, :c=>9} 

3 Comments

Thanks @Stefan : P
@CarySwoveland you don't need a default value in #2, the inner block is only executed if the key exists in both hashes.
Thanks, @Stefan. It's late and I'm bushed from building stairs all day, so the little grey cells seem to have nodded off.

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.