Enumerable#select used to return actual values

I'm pretty sure select used to use the actual value of the called block, instead of treating it as just a truthy/falsey boolean. I know this is unconventional, but it's a really nice, compact way of expressing map and filter in one shot, like list comprehension:

(1..10).select { |a| a * a if a > 5 }

Was it ever there, or did I just have a dream about it? It's easy to implement... just wondering.

Mike

I'm pretty sure select used to use the actual value of the called block, instead of treating it as just a truthy/falsey boolean.

I am pretty sure it did never. Maybe you have a combination with to_enum in mind or rather inject?

I know this is unconventional, but it's a really nice, compact way of expressing map and filter in one shot, like list comprehension:

(1..10).select { |a| a * a if a > 5 }

Was it ever there, or did I just have a dream about it? It's easy to implement... just wondering.

Maybe 1.9 has a nifty trick, I don't use it that often yet.

As said, inject is always a good candidate for this:

irb(main):005:0> (1..10).inject() {|r,a| r << (a*a) if a > 5; r}
=> [36, 49, 64, 81, 100]

Kind regards

  robert

···

On 30.11.2008 04:46, Mike Austin wrote:

I always thought it would be nice if Ruby had a method for this.
Facets' provides #compact_map. Perhaps not the sexiest name (once upon
a time it was called #collect_if), but it's describes the behavior
properly.

T.

···

On Nov 29, 10:39 pm, Mike Austin <"mike[nospam]"@mike-austin.com> wrote:

I'm pretty sure select used to use the actual value of the called block,
instead of treating it as just a truthy/falsey boolean. I know this is
unconventional, but it's a really nice, compact way of expressing map and
filter in one shot, like list comprehension:

(1..10).select { |a| a * a if a > 5 }

Was it ever there, or did I just have a dream about it? It's easy to
implement... just wondering.

..
# (1..10).select { |a| a * a if a > 5 }

the difficulty there is that there is no clear separation bw the selection logic and the mapping logic

# Was it ever there, or did I just have a dream about it?
# It's easy to implement... just wondering.

it's easy in 1.9..

p (0..10).select_with_map ->(x){x<5}, ->(x){x*x}

[0, 1, 4, 9, 16]

one could also do partitioning if 3rd block is provided (wc catches the else portion)

p (0..10).select_with_map ->(x){x<5}, ->(x){x*x}, ->(x){x+x}

[[0, 1, 4, 9, 16], [10, 12, 14, 16, 18, 20]]

but still i prefer {|x| x<5} over ->(x){x<5}
or maybe, ->{|x| x<5} over ->(x){x<5}

···

From: Mike Austin [mailto:"mike[nospam]"@mike-austin.com]

This is what I do:

(1..10).collect{ |a| a * a if a > 5 }.compact

The only time this doesn't work is when you want to preserve nils in
your original array.

-- Mark.

···

On Nov 29, 10:46 pm, Mike Austin <"mike[nospam]"@mike-austin.com> wrote:

I'm pretty sure select used to use the actual value of the called block,
instead of treating it as just a truthy/falsey boolean. I know this is
unconventional, but it's a really nice, compact way of expressing map and
filter in one shot, like list comprehension:

(1..10).select { |a| a * a if a > 5 }

Was it ever there, or did I just have a dream about it? It's easy to
implement... just wondering.

As Robert was the first to suggest inject I am left with the less
attractive joices :wink:

a.map{ |a| a > 5 ? a*a: nil}.compact # does not work for any &blk of course

or

myselection = proc{ |a| a*a if a > 5}
a.select(&myselection).map(&myselection)

or

module Enumerable
   def map_selection &blk
      select( &blk ).map( &blk )
   end
end

HTH
Robert

···

On Sun, Nov 30, 2008 at 8:54 AM, Robert Klemme <shortcutter@googlemail.com> wrote:

On 30.11.2008 04:46, Mike Austin wrote:

I'm pretty sure select used to use the actual value of the called block,
instead of treating it as just a truthy/falsey boolean.

I am pretty sure it did never. Maybe you have a combination with to_enum in
mind or rather inject?

I know this is unconventional, but it's a really nice, compact way of
expressing map and filter in one shot, like list comprehension:

(1..10).select { |a| a * a if a > 5 }

Was it ever there, or did I just have a dream about it? It's easy to
implement... just wondering.

Maybe 1.9 has a nifty trick, I don't use it that often yet.

As said, inject is always a good candidate for this:

irb(main):005:0> (1..10).inject() {|r,a| r << (a*a) if a > 5; r}

--
Ne baisse jamais la tête, tu ne verrais plus les étoiles.

Robert Dober :wink:

Hi --

···

On Sun, 30 Nov 2008, Robert Klemme wrote:

On 30.11.2008 04:46, Mike Austin wrote:

I'm pretty sure select used to use the actual value of the called block, instead of treating it as just a truthy/falsey boolean.

I am pretty sure it did never. Maybe you have a combination with to_enum in mind or rather inject?

I know this is unconventional, but it's a really nice, compact way of expressing map and filter in one shot, like list comprehension:

(1..10).select { |a| a * a if a > 5 }

Was it ever there, or did I just have a dream about it? It's easy to implement... just wondering.

Maybe 1.9 has a nifty trick, I don't use it that often yet.

(0..10).each_with_object() {|e,a| a << (e * e) if e > 5 }

Basically inject with a sticky accumulator.

David

--
Rails training from David A. Black and Ruby Power and Light:
INTRO TO RAILS (Jan 12-15) | ADVANCING WITH RAILS (Jan 19-22) *
Both in Fort Lauderdale, FL * Co-taught with Patrick Ewing
See http://www.rubypal.com for details
Coming in 2009: The Well-Grounded Rubyist (http://manning.com/black2\)

Oh, I remember why it is called #compact_map now, rather then some
more concise name. And I've been meaning to bring it up again. Why not
let #compact itself take a block to do this?

T.

···

On Nov 30, 6:45 am, Trans <transf...@gmail.com> wrote:

On Nov 29, 10:39 pm, Mike Austin <"mike[nospam]"@mike-austin.com> > wrote:

> I'm pretty sure select used to use the actual value of the called block,
> instead of treating it as just a truthy/falsey boolean. I know this is
> unconventional, but it's a really nice, compact way of expressing map and
> filter in one shot, like list comprehension:

> (1..10).select { |a| a * a if a > 5 }

> Was it ever there, or did I just have a dream about it? It's easy to
> implement... just wondering.

I always thought it would be nice if Ruby had a method for this.
Facets' provides #compact_map. Perhaps not the sexiest name (once upon
a time it was called #collect_if), but it's describes the behavior
properly.

Hi --

···

On Tue, 2 Dec 2008, Peña, Botp wrote:

From: Mike Austin [mailto:"mike[nospam]"@mike-austin.com]
..
# (1..10).select { |a| a * a if a > 5 }

the difficulty there is that there is no clear separation bw the selection logic and the mapping logic

# Was it ever there, or did I just have a dream about it?
# It's easy to implement... just wondering.

it's easy in 1.9..

p (0..10).select_with_map ->(x){x<5}, ->(x){x*x}

[0, 1, 4, 9, 16]

I don't see that method in 1.9. Which version are you using?

David

--
Rails training from David A. Black and Ruby Power and Light:
INTRO TO RAILS (Jan 12-15), Fort Lauderdale, FL
See http://www.rubypal.com for details
Coming in 2009: The Well-Grounded Rubyist (http://manning.com/black2\)

Peña wrote:

From: Mike Austin [mailto:"mike[nospam]"@mike-austin.com] .
# (1..10).select { |a| a * a if a > 5 }

the difficulty there is that there is no clear separation bw the selection logic and the mapping logic

that's... the idea.

# Was it ever there, or did I just have a dream about it? # It's easy to implement... just wondering.

it's easy in 1.9..

p (0..10).select_with_map ->(x){x<5}, ->(x){x*x}

[0, 1, 4, 9, 16]

The new syntax looks like a function got run over by a lambda. Twice.
I guess it wasn't possible to make them look like lambdas?

one could also do partitioning if 3rd block is provided (wc catches the else portion)

p (0..10).select_with_map ->(x){x<5}, ->(x){x*x}, ->(x){x+x}

[[0, 1, 4, 9, 16], [10, 12, 14, 16, 18, 20]]

but still i prefer {|x| x<5} over ->(x){x<5}
or maybe, ->{|x| x<5} over ->(x){x<5}

I wouldn't mind "&{|x| x < 5}" - shorthand for "&lambda {|x| x < 5}" which you can pass to functions that require a block:

(1..10).map &lambda {|n| n * n}

Mike

> I'm pretty sure select used to use the actual value of the called block,
> instead of treating it as just a truthy/falsey boolean. I know this is
> unconventional, but it's a really nice, compact way of expressing map and
> filter in one shot, like list comprehension:

> (1..10).select { |a| a * a if a > 5 }

> Was it ever there, or did I just have a dream about it? It's easy to
> implement... just wondering.

This is what I do:

(1..10).collect{ |a| a * a if a > 5 }.compact

The only time this doesn't work is when you want to preserve nils in
your original array.

And that's exactly what I suggested for #compact, to take a block but
faster b/c it's one pass.

T.

···

On Dec 4, 9:44 am, Mark Thomas <m...@thomaszone.com> wrote:

On Nov 29, 10:46 pm, Mike Austin <"mike[nospam]"@mike-austin.com> > wrote:

-- Mark.

Hi --

···

On Sun, 30 Nov 2008, Robert Dober wrote:

On Sun, Nov 30, 2008 at 8:54 AM, Robert Klemme > <shortcutter@googlemail.com> wrote:

On 30.11.2008 04:46, Mike Austin wrote:

I'm pretty sure select used to use the actual value of the called block,
instead of treating it as just a truthy/falsey boolean.

I am pretty sure it did never. Maybe you have a combination with to_enum in
mind or rather inject?

I know this is unconventional, but it's a really nice, compact way of
expressing map and filter in one shot, like list comprehension:

(1..10).select { |a| a * a if a > 5 }

Was it ever there, or did I just have a dream about it? It's easy to
implement... just wondering.

Maybe 1.9 has a nifty trick, I don't use it that often yet.

As said, inject is always a good candidate for this:

irb(main):005:0> (1..10).inject() {|r,a| r << (a*a) if a > 5; r}

As Robert was the first to suggest inject I am left with the less
attractive joices :wink:

a.map{ |a| a > 5 ? a*a: nil}.compact # does not work for any &blk of course

or

myselection = proc{ |a| a*a if a > 5}
a.select(&myselection).map(&myselection)

or

module Enumerable
  def map_selection &blk
     select( &blk ).map( &blk )
  end
end

There's also:

   res =
   (1..10).each {|e| res << (e * e) if e > 5 }
   res

No shame in a local variable now and then :slight_smile:

David

--
Rails training from David A. Black and Ruby Power and Light:
INTRO TO RAILS (Jan 12-15) | ADVANCING WITH RAILS (Jan 19-22) *
Both in Fort Lauderdale, FL * Co-taught with Patrick Ewing
See http://www.rubypal.com for details
Coming in 2009: The Well-Grounded Rubyist (http://manning.com/black2\)

Hi,

···

In message "Re: Enumerable#select used to return actual values" on Sun, 30 Nov 2008 19:47:13 +0900, "David A. Black" <dblack@rubypal.com> writes:

(0..10).each_with_object() {|e,a| a << (e * e) if e > 5 }

Basically inject with a sticky accumulator.

#each_with_object is an interesting concept. Maybe we can add it to
the Enumerable if we can come up with a better name.

              matz.

Hi,

···

In message "Re: Enumerable#select used to return actual values" on Fri, 5 Dec 2008 00:47:45 +0900, Trans <transfire@gmail.com> writes:

(1..10).collect{ |a| a * a if a > 5 }.compact

The only time this doesn't work is when you want to preserve nils in
your original array.

And that's exactly what I suggested for #compact, to take a block but
faster b/c it's one pass.

I don't deny the existence of use case of such method (although I
cannot think of any realistic one right now), but its name should not
be #compact, since it does far more than compacting the receiver.

              matz.

Not at all, and it is often the *fastest* solution as, unfortunately,
#inject is slow.

Robert

···

On Sun, Nov 30, 2008 at 11:13 AM, David A. Black <dblack@rubypal.com> wrote:

There's also:

res =
(1..10).each {|e| res << (e * e) if e > 5 }
res

No shame in a local variable now and then :slight_smile:

I take it that #each_with_object returns the accumulator, ie.

  a = (0..10).each_with_object() {|e,a| a << (e * e) if e > 5 }

Since in 1.9 the block parameter is local to the block.

As for a better name, maybe #each can just take an argument.

  (0..10).each() {|e,a| a << (e * e) if e > 5 }

Or there's #accumulate, although the object doesn't necessarily have
to be used according to that meaning.

Do you remain against the idea of #compact taking a block?

T.

···

On Nov 30, 6:24 pm, Yukihiro Matsumoto <m...@ruby-lang.org> wrote:

Hi,

In message "Re: Enumerable#select used to return actual values" > on Sun, 30 Nov 2008 19:47:13 +0900, "David A. Black" <dbl...@rubypal.com> writes:

>(0..10).each_with_object() {|e,a| a << (e * e) if e > 5 }
>
>Basically inject with a sticky accumulator.

#each_with_object is an interesting concept. Maybe we can add it to
the Enumerable if we can come up with a better name.

Maybe the difficulty to find a name points to a problem...
I was just thinking that this looks really cool

.with_each( 1..10 ){ |o, e| o << e if e > 5 }

What do you think, surely adding #with_each to #Object shall be very
carefully considered, but I like the syntax, err yes I have already
said that :wink:

Robert

···

On Mon, Dec 1, 2008 at 12:24 AM, Yukihiro Matsumoto <matz@ruby-lang.org> wrote:

#each_with_object is an interesting concept. Maybe we can add it to
the Enumerable if we can come up with a better name.

                                                       matz.

--
Ne baisse jamais la tête, tu ne verrais plus les étoiles.

Robert Dober :wink:

Hi --

Hi,

>(0..10).each_with_object() {|e,a| a << (e * e) if e > 5 }
>
>Basically inject with a sticky accumulator.

#each_with_object is an interesting concept. Maybe we can add it to
the Enumerable if we can come up with a better name.

But it's in Enumerable already, in 1.9.

RUBY_DESCRIPTION

=> "ruby 1.9.0 (2008-11-12 revision 20227) [i386-darwin9.5.0]"

Enumerable.instance_methods(false).grep(/object/)

=> [:each_with_object]

David

···

On Mon, 1 Dec 2008, Yukihiro Matsumoto wrote:

In message "Re: Enumerable#select used to return actual values" > on Sun, 30 Nov 2008 19:47:13 +0900, "David A. Black" <dblack@rubypal.com> writes:

--
Rails training from David A. Black and Ruby Power and Light:
INTRO TO RAILS (Jan 12-15), Fort Lauderdale, FL
See http://www.rubypal.com for details
Coming in 2009: The Well-Grounded Rubyist (http://manning.com/black2\)

Hmmm
just a little brainstorming on this
[1, nil, false].compact --> [1]
[1, nil, false].compact_by{ |x| x.nil?} --> [1, false]

o = Object::new
a.collect{ |x| some_condition(x) ? x : o}.compact_by{ |x| x==o}

But actually the implementation is *easy* :wink:
module Enumerable
   alias_method :compact_by, :reject ### :wink:
end

However what about

module Enumerable
   alias_method :__old_reject__, :reject
   def reject( *args, &blk )
        raise SomeDescriptiveError unless blk.nil? || args.empty?
        return __old_reject__( &blk ) if blk
        __old_reject__{ |x| args.include? x }
   end
end

I guess I might put this into Labrador :wink:

Cheers
Robert

or

···

On Thu, Dec 4, 2008 at 5:07 PM, Yukihiro Matsumoto <matz@ruby-lang.org> wrote:

Hi,

In message "Re: Enumerable#select used to return actual values" > on Fri, 5 Dec 2008 00:47:45 +0900, Trans <transfire@gmail.com> writes:

>> (1..10).collect{ |a| a * a if a > 5 }.compact
>>
>> The only time this doesn't work is when you want to preserve nils in
>> your original array.
>
>And that's exactly what I suggested for #compact, to take a block but
>faster b/c it's one pass.

I don't deny the existence of use case of such method (although I
cannot think of any realistic one right now), but its name should not
be #compact, since it does far more than compacting the receiver.

                                                       matz.

--
Ne baisse jamais la tête, tu ne verrais plus les étoiles.

Robert Dober :wink:

#transform ?

Take something, transform it into something else.

Marcelo

···

On Thu, Dec 4, 2008 at 10:07 AM, Yukihiro Matsumoto <matz@ruby-lang.org> wrote:

I don't deny the existence of use case of such method (although
I cannot think of any realistic one right now), but its name
should not be #compact, since it does far more than compacting
the receiver.