"Gavin Sinclair" <gsinclair / soyabean.com.au> 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}
> > => #<Proc:0x100c4978@(irb):32>
> > 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