68

This is my array

[{:amount=>10, :gl_acct_id=>1, :alt_amount=>20}, {:amount=>20, :gl_acct_id=>2
, :alt_amount=>30}]

i want result

[{:amount => 30}] or {:amount = 30}

Any idea?

8 Answers 8

93

Ruby versions >= 2.4.0 has an Enumerable#sum method. So you can do

arr.sum {|h| h[:amount] }
Sign up to request clarification or add additional context in comments.

3 Comments

probably the best answer IMHO
But this returns 30 and not the desired result [{:amount => 30}] or {:amount = 30}
@tvw Which is trivial once you get the sum. Also this answer was posted 6 years after OP had asked the question. So my intension was to help any one who comes here with a similar problem. :)
73

array.map { |h| h[:amount] }.sum

2 Comments

and while using rails, could be shorter: array.sum {|h| h[:amount]}
This creates a temporary array, which can be avoided.
66

You can use inject to sum all the amounts. You can then just put the result back into a hash if you need to.

arr = [{:amount=>10, :gl_acct_id=>1, :alt_amount=>20}, {:amount=>20, :gl_acct_id=>2, :alt_amount=>30}]    
amount = arr.inject(0) {|sum, hash| sum + hash[:amount]} #=> 30
{:amount => amount} #=> {:amount => 30}

2 Comments

thank you @sepp2k this is very useful. in the answer above we have to name the key - what if we want the sum for all the keys - (i.e. we don't want to name them individually - do you know how we would solve that?)
I have the same issue, my hash is [2, #<BigDecimal:7f29fe6164b0,'0.1256E4',9(18)>, 4, #<BigDecimal:7f29fe6163e8,'0.281E4',9(18)>, 3, #<BigDecimal:7f29fe6162a8,'0.24E4',9(18)>] and I wish to sum the values which have no name.
13

This is one way to do it:

a = {amount:10,gl_acct_id:1,alt_amount:20},{amount:20,gl_acct_id:2,alt_amount:30}
a.map {|h| h[:amount] }.reduce(:+)

However, I get the feeling that your object model is somewhat lacking. With a better object model, you would probably be able to do something like:

a.map(&:amount).reduce(:+)

Or even just

a.sum

Note that as @sepp2k pointed out, if you want to get out a Hash, you need to wrap it in a Hash again.

3 Comments

@mittag can you tell me what should be a better object model ?? so i can use this one ... a.map(&:amount).reduce(:+)
@krunal: Most basic example: Foo = Struct.new(:amount, :gl_acct_id, :alt_amount); a = [Foo.new(10, 1, 20), Foo.new(20,2,30)]; a.map(&:amount).inject(:+) #=> 30
@sepp2k: Thanks! Missed that one.
6

why not pluck?

ary = [{:amount=>10, :gl_acct_id=>1, :alt_amount=>20}, {:amount=>20, :gl_acct_id=>2, :alt_amount=>30}]

ary.pluck(:amount).sum

# for more reliability
ary.pluck(:amount).compact.sum

2 Comments

Only rails thought, from 5.0 and above api.rubyonrails.org/classes/Enumerable.html#method-i-pluck
This would require unnecessarily iterating over the array several times
4
[{
    :amount=>10,
    :gl_acct_id=>1,
    :alt_amount=>20
},{
    :amount=>20,
    :gl_acct_id=>2,
    :alt_amount=>30
}].sum { |t| t[:amount] }

2 Comments

Welcome to Stack Overflow! It's usually better to explain your answers, rather than just posting code.
Welcome to Stack Overflow! Although this code may help to solve the problem, it doesn't explain why and/or how it answers the question. Providing this additional context would significantly improve its long-term educational value. Please edit your answer to add explanation, including what limitations and assumptions apply.
3

If we are having only a single element in all the hashes in a array and also keys were different ?

Here is the solution I found:

Sum of the values:

x = [{"a" => 10},{"b" => 20},{"d" => 30}]

Solution:

x.inject(0){|sum, hash| sum+= hash.values.join.to_i }

Also we can do:

x.inject(0){|sum, hash| sum+= hash.values.sum }

Comments

-2
total=0
arr = [{:amount=>10, :gl_acct_id=>1, :alt_amount=>20}, {:amount=>20, :gl_acct_id=>2, :alt_amount=>30}]
arr.each {|x| total=total+x[:amount]}
puts total

1 Comment

that is mostly equivalent to this one-liner: total = arr.inject(0) {|sum, hash| sum += hash[:amount]}

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.