From: Mauricio Fernandez Date: 2006-04-13T23:32:44+09:00 Subject: Re: map_if, collect_if ??? On Thu, Apr 13, 2006 at 10:53:24PM +0900, Robert Dober wrote: > On 4/13/06, Robert Dober wrote: > module Enumerable > def map_if > map{ |x| (r = yield(x)) ? r : nil}.compact > end > end > > that one might do as a comprimise between speed, elegance and sanity? It's quite slow (two blocks in use...). If you care a bit about performance (but not enough to use C), def map_if(&b) a = map(&b) a.delete(false) # to get the same semantics as select{|e| e} a.compact! a end requires half as much mem in the worst case as, and runs ~60% faster than map(&b).select{|e| e}: RUBY_VERSION # => "1.8.4" module Enumerable def map_if(&b) a = map(&b) a.delete(false) # to get the same semantics as select{|e| e} a.compact! a end def map_if2(&b) map(&b).select{|e| e} end def map_if3 inject([]){|s,x| (v = yield(x)) ? s << v : s } end def map_if4 map{|x| (r = yield(x)) ? r : nil}.compact end end require 'benchmark' TIMES = 100 Benchmark.bmbm(10) do |bm| arr = (1..10000).to_a bm.report("compact!"){ TIMES.times{ arr.map_if{true} } } bm.report("select"){ TIMES.times{ arr.map_if2{ true} } } bm.report("inject"){ TIMES.times{ arr.map_if3{ true} } } bm.report("? : test"){ TIMES.times{ arr.map_if4{ true} } } # the block wouldn't let us measure the actual performance: #bm.report("compact!"){ TIMES.times{ arr.map_if{|x| x % 7 == 0 and x} } } #bm.report("select"){ TIMES.times{ arr.map_if2{|x| x % 7 == 0 and x} } } #bm.report("inject"){ TIMES.times{ arr.map_if3{|x| x % 7 == 0 and x} } } #bm.report("? : test"){ TIMES.times{ arr.map_if4{|x| x % 7 == 0 and x} } } end # >> Rehearsal --------------------------------------------- # >> compact! 0.380000 0.000000 0.380000 ( 0.431046) # >> select 0.650000 0.000000 0.650000 ( 0.725197) # >> inject 4.300000 0.020000 4.320000 ( 4.647794) # >> ? : test 2.400000 0.010000 2.410000 ( 2.551757) # >> ------------------------------------ total: 7.760000sec # >> # >> user system total real # >> compact! 0.390000 0.000000 0.390000 ( 0.408975) # >> select 0.640000 0.010000 0.650000 ( 0.747967) # >> inject 3.880000 0.010000 3.890000 ( 4.211830) # >> ? : test 2.070000 0.000000 2.070000 ( 2.199076) -- Mauricio Fernandez - http://eigenclass.org - singular Ruby