From: Mike Harris Date: 2006-11-16T04:08:48+09:00 Subject: Re: Design problem with 'inject' Jacob Fugal wrote: > On 11/14/06, Gary Boone wrote: > >> arr.inject(0) do |sum, i| >> next if (i==3) >> sum += i >> done > > > Others have already posted clarifying the semantics of inject and > proposing alternate solutions, so I won't bother with that. I just > wanted to point out another alternate: > > arr.select{ |i| i != 3 }.inject(0){ |sum, i| sum + i } > > I like to use block-taking functions on Enumerables like unix pipes > and let the body of each block do the simplest thing possible. > > The only potential drawback to breaking the filter apart like this is > that the current implementation of ruby turns this into two loops. If > your array is large, this can be a problem. But for most cases where > you're not doing number crunching, the inefficiency is negligible. > > Just another possibility... > > Jacob Fugal > > Agree 100% on the use of select On performance, it depends on what you're doing. The more items you want to exclude, the better select does. tm is just a method to time the block tm("One Loop") { a.inject { |s,i| (false) ? s+i : s } } tm("Two Loops") { a.select { |x| false }.inject(0) { |s,i| s+i } } Timing One Loop : 2 Seconds 188 Milliseconds Timing Two Loops : 0 Seconds 327 Milliseconds tm("One Loop") { a.inject { |s,i| (x%10==0) ? s+i : s } } tm("Two Loops") { a.select { |x| x%10==0 }.inject(0) { |s,i| s+i } } Timing One Loop : 3 Seconds 32 Milliseconds Timing Two Loops : 1 Second 234 Milliseconds tm("One Loop") { a.inject { |s,i| (x%2==0) ? s+i : s } } tm("Two Loops") { a.select { |x| x%2==0 }.inject(0) { |s,i| s+i } } Timing One Loop : 3 Seconds 907 Milliseconds Timing Two Loops : 3 Seconds 188 Milliseconds tm("One Loop") { a.inject { |s,i| (x%10!=0) ? s+i : s } } tm("Two Loops") { a.select { |x| x%10!=0 }.inject(0) { |s,i| s+i } } Timing One Loop : 5 Seconds 48 Milliseconds Timing Two Loops : 5 Seconds 235 Milliseconds tm("One Loop") { a.inject { |s,i| (true) ? s+i : s } } tm("Two Loops") { a.select { |x| true }.inject(0) { |s,i| s+i } } Timing One Loop : 4 Seconds 532 Milliseconds Timing Two Loops : 5 Seconds 314 Milliseconds