I am having trouble with the syntax for reduce. I have a hash of the following format:
H = {\"Key1\" => 1, \"Key2\" => 2}
I would like t
I know I'm excavating this one, but if you happen to use Rails, the .sum method can help:
H = {"Key1" => 1, "Key2" => 2}
=> {"Key1"=>1, "Key2"=>2}
> H.values.sum
=> 3
Advantage is that it returns 0
on empty hashes:
> {}.values.sum
=> 0
> {}.values.reduce(:+)
=> nil
I noticed it was Rails-specific only after typing this answer. I know the OP didn't add the Rails tag, but I figured it might be useful for people stopping by.
Note that as of Ruby 2.4.0, .sum is now available.
In case of a complex hash it might be easier to map it first to an array of values, then reduce:
values = H.map do |k, v|
# some complex logic here
end
values.reduce(:+)
Or values.reduce(0, :+)
if the array might be empty.
You can make elem
contain the value by splitting it up in 2 variables:
H.reduce(0) {|memo, (key, val)| memo += val}
Try this:
H.reduce(0) { |memo, elem| memo += elem[1] }
or
H.reduce(0) { |memo, (key, value)| memo += value }
Use Enumerable#reduce, if you're ok with getting nil
if the hash happens to be empty:
H.values.reduce(:+) # => 3
Hash.new.values.reduce(:+) # => nil
To safely get 0
when the hash is empty, use:
H.values.reduce(0) { |sum,x| sum + x } # or...
H.reduce(0) { |sum,(key,val)| sum + val } # ...if you need to inspect the key
Here's a quick benchmark, for kicks. Note that it appears to be slightly faster to reduce just the values rather than values from the key/value pairs:
user system total real
H.values.reduce(:+) 4.510000 0.080000 4.590000 ( 4.595229)
H.values.reduce(0) {...} 4.660000 0.080000 4.740000 ( 4.739708)
H.reduce(0) {...} 5.160000 0.070000 5.230000 ( 5.241916)
require 'benchmark'
size = 1_000
hash = Hash[* Array.new(size*2) { rand } ]
N=10_000
Benchmark.bm(24) do |x|
x.report('H.values.reduce(:+)') { N.times { hash.dup.values.reduce(:+) } }
x.report('H.values.reduce(0) {...}') { N.times { hash.dup.values.reduce(0) { |sum,x| sum + x } } }
x.report('H.reduce(0) {...}') { N.times { hash.dup.reduce(0) { |sum,(_,v)| sum + v } } }
end
h = {"Key1" => 1, "Key2" => 2}
h.values.inject(0){|f,v| f += v.to_i }
# => 3
or
h.values.inject(:+)
# => 3