From: Robert Klemme Date: 2004-05-13T17:23:52+09:00 Subject: Re: in search of a compelling reason to use ruby.... "Gavin Sinclair" schrieb im Newsbeitrag news:43228.129.78.228.114.1084421428.squirrel@webmail.imagineis.com... > Robert wrote: > > > You can make your life even simpler with: > > > > module Criterion > > def self.create(&b) > > def b.===(x); call(x);end > > b > > end > > end > > > > irb(main):031:0> a = %w{a bb ccc} > > => ["a", "bb", "ccc"] > > irb(main):032:0> crit = Criterion.create {|x| x.length > 2} > > => # > > irb(main):033:0> a.grep(crit) {|x| "(#{x})"} > > => ["(ccc)"] > > How is this simpler than > > a.select { |x| x.length > 2 } > > ? > > OIC. You're using the block form of grep to save yourself a map. I don't > much like it, though, because the filtering predicate is removed from the > place where it's used, wasting the beuaty of blocks. Yeah, that's true, although you could do a.grep( Criterion.create {|x| x.length > 2} ) {|x| "(#{x})"} or even if you define Criterion as method in Kernel: a.grep( Criterion {|x| x.length > 2} ) {|x| "(#{x})"} > Clever, though, and probably useful in some situations (e.g. where you're > doing *lots* of filtering and mapping :) Exactly. I thought of a situation where you use this idiom often and you have Criterion as a lib module that you use over and over again. I forgot to mention that there is - of course - a shorter ad hoc solution with #inject. Maybe it's not as easy to read as others, but it's more efficient than select{}.map{} because you do only one iteration. Here it is: irb(main):005:0> a = %w{a bb ccc} => ["a", "bb", "ccc"] irb(main):006:0> a.inject([]) {|arr,x| arr << "(#{x})" if /^[ab]/ =~ x; arr} => ["(a)", "(bb)"] irb(main):007:0> a.inject([]) {|arr,x| arr << "(#{x})" if x.length > 2; arr} => ["(ccc)"] Regards robert