Enumerable#select used to return actual values

M

Mike Austin

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
 
R

Robert Klemme

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
 
R

Robert Dober

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 ;)


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

or

myselection =3D 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
--=20
Ne baisse jamais la t=EAte, tu ne verrais plus les =E9toiles.

Robert Dober ;)
 
D

David A. Black

Hi --

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 ;)


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 :)


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)
 
R

Robert Dober

There's also:

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

No shame in a local variable now and then :)
Not at all, and it is often the *fastest* solution as, unfortunately,
#inject is slow.

Robert
 
D

David A. Black

Hi --

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


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)
 
T

Trans

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. =A0I 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? =A0It'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.

T.
 
J

James Gray

There's also:

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

No shame in a local variable now and then :)
Not at all, and it is often the *fastest* solution as, unfortunately,
#inject is slow.

My opinion is that if inject() is really the biggest time sync in your
code, you're in big trouble. ;)

James Edward Gray II
 
J

James Gray

There's also:

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

No shame in a local variable now and then :)
Not at all, and it is often the *fastest* solution as, unfortunately,
#inject is slow.

My opinion is that if inject() is really the biggest time sync in
your code, you're in big trouble. ;)

Well, I meant big trouble if you're still looking for optimizations.

If your code is instead fast enough and inject() is the biggest time
sync left, you are in great shape.

Either way, changing out inject() for speed seems silly to me.

James Edward Gray II
 
T

Trans

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.

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.
 
R

Robert Dober

My opinion is that if inject() is really the biggest time sync in your co= de,
you're in big trouble. ;)
Not really James, I have written same tiny little patches for Facets
to replace inject with the local variable- each technique because 30%
faster is important in a library.
Tom was kind enough to agree with this and released the patches, but
the code is less compact now for no necessary reason.
But maybe I should stop complaining and file a bug report ;)
Cheers
Robert

--=20
Ne baisse jamais la t=EAte, tu ne verrais plus les =E9toiles.

Robert Dober ;)
 
J

James Gray

Not really James, I have written same tiny little patches for Facets
to replace inject with the local variable- each technique because 30%
faster is important in a library.

You may have a point there. I'm pretty sure Merb has done similar
optimizations.

I'm sticking to my guns though. inject() would be very, very low on
the list of things I try to optimize away.

I want to use Ruby as Ruby first and worry about speed second, if ever.

James Edward Gray II
 
R

Robert Dober

#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.
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 ;)

Robert



--=20
Ne baisse jamais la t=EAte, tu ne verrais plus les =E9toiles.

Robert Dober ;)
 
M

Mike Austin

Robert said:
#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.
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 about just "each_with()"?

(1..10).each_with([]) { |o, e| o << e if e > 5 }

It goes together well with "each_with_index()", imho.
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 ;)

Robert

Mike
 
F

Florian Aßmann

What about Enumerable.into(something) ...

Regards
Florian

Am 01.12.2008 um 04:39 schrieb Mike Austin:
Robert said:
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.
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 about just "each_with()"?

(1..10).each_with([]) { |o, e| o << e if e > 5 }

It goes together well with "each_with_index()", imho.
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 ;)
Robert

Mike
 
P

Peña, Botp

From: Mike Austin [mailto:"mike[nospam]"@mike-austin.com]=20
..
# (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? =20
# 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}
 
M

Mike Austin

Peña said:
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
 
M

Mark Thomas

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.

-- Mark.
 
T

Trans

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.
 
R

Robert Dober

Hi,

In message "Re: Enumerable#select used to return actual values"

|> (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.
Hmmm
just a little brainstorming on this
[1, nil, false].compact --> [1]
[1, nil, false].compact_by{ |x| x.nil?} --> [1, false]

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

But actually the implementation is *easy* ;)
module Enumerable
alias_method :compact_by, :reject ### ;)
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 ;)

Cheers
Robert

or




--=20
Ne baisse jamais la t=EAte, tu ne verrais plus les =E9toiles.

Robert Dober ;)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,009
Latest member
GidgetGamb

Latest Threads

Top