Phrogz wrote:
Is there an idiom for doing something to the first value as part of an
inject? Or do I need to .map{}.inject{}?
class Array
def sum
inject(0){ |total, entry| total + entry.to_f }
end
def product
inject(1){ |total, entry| total * entry.to_f }
end
def running_difference
inject{ |total, entry| total - entry.to_f }
end
def running_divide
inject{ |total, entry| total / entry.to_f }
end
end
Personally I would definitively not include those .to_f's because those make the code less useful. Consider for example an array that contains Bignums - you force them to floats and get imprecise float match as opposed to precise int math. Let #coerce() do it's work.
Also, Enumerable seems a better place for such general methods.
a1 = [5,4,3,2,1]
p a1.sum
#=> 15.0
p a1.product
#=> 120.0
p a1.running_difference
#=> -5.0
p a1.running_divide
#=> 0.208333333333333
a2 = ["5","4","3","2","1"]
p a2.sum
#=> 15.0
p a2.product
#=> 120.0
p a2.running_difference
#=> tmp.rb:9:in `running_difference': undefined method `-' for
"5":String (NoMethodError)
#=> from tmp.rb:36:in `inject'
#=> from tmp.rb:9:in `running_difference'
#=> from tmp.rb:31
IMHO the map or map! approach is better because you get better modularization. If you want the performance you can use inject directly - but for those general methods I would not have these conversions.
Oh, wait, you could do this:
module Enumerable
def sum(*init,&b)
b ||= lambda {|x| x}
inject(*init) {|x,y| x + b[y]}
end
end
irb(main):010:0> %w{1 2 3 4}.sum(0) {|x| x.to_i}
=> 10
irb(main):011:0> %w{1 2 3 4}.sum
=> "1234"
Or even
module Enumerable
def agg(op,*init,&b)
b ||= lambda {|x| x}
inject(*init) {|x,y| x.send(op, b[y])}
end
end
irb(main):019:0* %w{1 2 3 4}.agg(:*, 1) {|x| x.to_i}
=> 24
irb(main):020:0> %w{1 2 3 4}.agg(:+, 0) {|x| x.to_i}
=> 10
irb(main):022:0> %w{1 2 3 4}.agg(:+)
=> "1234"
Kind regards
robert