Summing values in a hash?

Hi,

Is there an inbuilt method to sum all values in a hash and return the result?

I.E something like puts hash[values].sum

If so could someone please point me at the correct section of the ruby docs?

thanks,
Jen.

You could try

hash.values.inject { |a, b| a + b }

Alternatively, you have the shorter form, inject(&:+) or inject(:+)
depending on your version of Ruby. 1.8.7 and higher should support all
three.

···

On Tue, Mar 22, 2011 at 12:57 PM, Jen <jen.bottom@gmail.com> wrote:

Is there an inbuilt method to sum all values in a hash and return the
result?

I.E something like puts hash[values].sum

There's no built in method to do that. You can do it with:

hash = { :a => 1, :b => 6, :c => 20 }

p hash.inject(0) { |sum, tuple| sum += tuple[1] } # => 27

···

On Tuesday, March 22, 2011 01:57:27 pm Jen wrote:

Hi,

Is there an inbuilt method to sum all values in a hash and return the
result?

I.E something like puts hash[values].sum

If so could someone please point me at the correct section of the ruby
docs?

thanks,
Jen.

Maybe write your own method because:
1. it may be quicker than searching for an "inbuilt" method;
2. it may run faster than using inject.

require "benchmark"
kt = 100_000
nn = 20

hash = Hash.new
(1 .. nn).each { |nv| hash[ nv.to_s ] = nv }
s1 = s2 = s3 = s4 = nil

class Hash
  def mysum()
    s = 0
    each_value { |v| s += v }
    s
  end
end

sv = (nn * (nn + 1)) / 2
puts; puts "summing 1..#{nn} #=> #{sv}; kt=#{kt};"

Benchmark.bmbm do |bm|
  bm.report("1"){kt.times{s1=hash.values.inject{ |a, b| a + b } }}
  bm.report("2"){kt.times{s2=hash.inject(0){ |sum, tuple| sum += tuple[1] } }}
  bm.report("3"){kt.times{s3=hash.inject(0){|a,(_,b)|a+b} }}
  bm.report("4"){kt.times{s4=hash.mysum }}
end
puts "#{s1.inspect} #{s2.inspect} #{s3.inspect} #{s4.inspect}"

ruby 1.9.1p430 (2010-08-16 revision 28998) [i386-mingw32]

summing 1..20 #=> 210; kt=100000;
        user system total real
1 3.057000 0.000000 3.057000 ( 3.057547)
2 4.587000 0.000000 4.587000 ( 4.630071)
3 4.524000 0.000000 4.524000 ( 4.525069)
4 1.653000 0.000000 1.653000 ( 1.650026)
210 210 210 210

summing 1..2000 #=> 2001000; kt=1000;
        user system total real
1 2.340000 0.000000 2.340000 ( 2.335036)
2 4.711000 0.000000 4.711000 ( 4.705072)
3 4.617000 0.000000 4.617000 ( 4.635071)
4 1.529000 0.000000 1.529000 ( 1.530024)
2001000 2001000 2001000 2001000

···

On Tue, Mar 22, 2011 at 12:57 PM, Jen <jen.bottom@gmail.com> wrote:

Is there an inbuilt method to sum all values in a hash and return the
result?
I.E something like puts hash[values].sum
If so could someone please point me at the correct section of the ruby docs?

You should rather use a different idiom because your solution breaks
for empty Hash:

irb(main):001:0> {}.values.inject {|a,b|a+b}
=> nil
irb(main):002:0> {}.values.inject(0) {|a,b|a+b}
=> 0

Kind regards

robert

···

On Tue, Mar 22, 2011 at 2:01 PM, Adam Prescott <mentionuse@gmail.com> wrote:

On Tue, Mar 22, 2011 at 12:57 PM, Jen <jen.bottom@gmail.com> wrote:

Is there an inbuilt method to sum all values in a hash and return the
result?

I.E something like puts hash[values].sum

You could try

hash.values.inject { |a, b| a + b }

Alternatively, you have the shorter form, inject(&:+) or inject(:+)
depending on your version of Ruby. 1.8.7 and higher should support all
three.

--
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/

slightly better, because working :wink:
    .inject(0){|a,(_,b)|a+b}
Cheers
R.

···

On Tue, Mar 22, 2011 at 2:05 PM, Robert Klemme <shortcutter@googlemail.com> wrote:

On Tue, Mar 22, 2011 at 2:01 PM, Adam Prescott <mentionuse@gmail.com> wrote:

On Tue, Mar 22, 2011 at 12:57 PM, Jen <jen.bottom@gmail.com> wrote:

Is there an inbuilt method to sum all values in a hash and return the
result?

I.E something like puts hash[values].sum

You could try

hash.values.inject { |a, b| a + b }

Alternatively, you have the shorter form, inject(&:+) or inject(:+)
depending on your version of Ruby. 1.8.7 and higher should support all
three.

You should rather use a different idiom because your solution breaks
for empty Hash:

irb(main):001:0> {}.values.inject {|a,b|a+b}
=> nil
irb(main):002:0> {}.values.inject(0) {|a,b|a+b}
=> 0

What do you mean by that? Where was my solution not working?

robert

···

On Tue, Mar 22, 2011 at 3:13 PM, Robert Dober <robert.dober@gmail.com> wrote:

On Tue, Mar 22, 2011 at 2:05 PM, Robert Klemme > <shortcutter@googlemail.com> wrote:

On Tue, Mar 22, 2011 at 2:01 PM, Adam Prescott <mentionuse@gmail.com> wrote:

On Tue, Mar 22, 2011 at 12:57 PM, Jen <jen.bottom@gmail.com> wrote:

Is there an inbuilt method to sum all values in a hash and return the
result?

I.E something like puts hash[values].sum

You could try

hash.values.inject { |a, b| a + b }

Alternatively, you have the shorter form, inject(&:+) or inject(:+)
depending on your version of Ruby. 1.8.7 and higher should support all
three.

You should rather use a different idiom because your solution breaks
for empty Hash:

irb(main):001:0> {}.values.inject {|a,b|a+b}
=> nil
irb(main):002:0> {}.values.inject(0) {|a,b|a+b}
=> 0

slightly better, because working :wink:
.inject(0){|a,(_,b)|a+b}

--
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/

jruby -e 'p( {:a=>42}.inject(0){|a,b|a+b})'
TypeError: Array can't be coerced into Fixnum
         + at org/jruby/RubyFixnum.java:333
  __file__ at -e:1
      each at org/jruby/RubyHash.java:1167
    inject at org/jruby/RubyEnumerable.java:816
    (root) at -e:1

I recon you where coming from Hash#values, however on applying the
code to an empy hash, where it works of course the reader could be
missled

Cheers
Robert

···

On Tue, Mar 22, 2011 at 4:08 PM, Robert Klemme <shortcutter@googlemail.com> wrote:

--
The 1,000,000th fibonacci number contains '42' 2039 times; that is
almost 30 occurrences more than expected (208988 digits).
N.B. The 42nd fibonacci number does not contain '1000000' that is
almost the expected 3.0e-06 times.

My code explicitly included #values so it would not be affected by the
error you posted - even for non empty Hash. Please read what I wrote.

Cheers

robert

···

On Tue, Mar 22, 2011 at 4:31 PM, Robert Dober <robert.dober@gmail.com> wrote:

On Tue, Mar 22, 2011 at 4:08 PM, Robert Klemme > <shortcutter@googlemail.com> wrote:
jruby -e 'p( {:a=>42}.inject(0){|a,b|a+b})'
TypeError: Array can't be coerced into Fixnum
+ at org/jruby/RubyFixnum.java:333
__file__ at -e:1
each at org/jruby/RubyHash.java:1167
inject at org/jruby/RubyEnumerable.java:816
(root) at -e:1

I recon you where coming from Hash#values, however on applying the
code to an empy hash, where it works of course the reader could be
missled

--
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/