Ruby Core Extension: Array#sum

It always bugs me that there is no #sum method on Arrays in Ruby. It's pretty easy to make your own:

class Array
  def sum
    inject(0) { |sum, i| sum + i }
  end
end

If you really want to be terse, you can use Symbol#to_proc:

class Array
  def sum
    inject(&:+) 
    # i.e. inject(&proc { |obj, *args| obj.send(:+, *args) })
  end
end

You could even just skip Symbol#to_proc, and pass in the method name you want to call on each accumulation:

class Array
  def sum
    inject(:+) 
    # i.e. inject { |sum, i| sum.send(:+, i) }
  end
end

However, I'm going to stick with the first version because I think it's clearer in the final implementation:

class Array
  def sum(method = nil, &block)
    if block_given?
      raise ArgumentError, "You cannot pass a block and a method!" if method
      inject(0) { |sum, i| sum + yield(i) }
    elsif method
      inject(0) { |sum, i| sum + i.send(method) }
    else
      inject(0) { |sum, i| sum + i }
    end
  end
end

This accepts no arguments, a method or a block. So, you can write things like:

>> [1,2,3].sum
=> 6
>> [1,2,3].sum(:to_f)
=> 6.0
>> [1,2,3].sum(&:to_f)
=> 6.0
>> [1,2,3].sum { |i| i+1 }
=> 9

A mix of code and design by Mark Dodwell, Rails developer and designer.