From: Robert Klemme Date: 2006-09-06T06:25:13+09:00 Subject: Re: Modifying the first value with #inject 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