[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

Injecting truth

kennethkunz

9/27/2006 10:08:00 PM

I had a scenario arise today where I needed an iterator with similar
semantics as Enumerable#all?, but non-short-circuiting. We came up with
a fairly elegant solution (imho), so I thought I'd be a good rubyzen
and share :)

1) First... the standard #all? (short-circuits):

irb> (1..5).all? { |i| puts i; i < 3 }
1
2
3
=> false

2) Non-short-circuiting version (injecting truth):

irb> (1..5).inject(true) { |retval, i| puts i; retval &&= (i < 3) }
1
2
3
4
5
=> false

3) One more way (though I like #2 better)

irb(main):016:0> (1..5).partition { |i| puts i; i < 3 }.last.empty?
1
2
3
4
5
=> false

-Ken

8 Answers

Mike Harris

9/27/2006 10:22:00 PM

0

Ken Kunz wrote:

>I had a scenario arise today where I needed an iterator with similar
>semantics as Enumerable#all?, but non-short-circuiting. We came up with
>a fairly elegant solution (imho), so I thought I'd be a good rubyzen
>and share :)
>
>1) First... the standard #all? (short-circuits):
>
>irb> (1..5).all? { |i| puts i; i < 3 }
>1
>2
>3
>=> false
>
>2) Non-short-circuiting version (injecting truth):
>
>irb> (1..5).inject(true) { |retval, i| puts i; retval &&= (i < 3) }
>1
>2
>3
>4
>5
>=> false
>
>3) One more way (though I like #2 better)
>
>irb(main):016:0> (1..5).partition { |i| puts i; i < 3 }.last.empty?
>1
>2
>3
>4
>5
>=> false
>
>-Ken
>
>
>
>
>
How about (1..5).map { |x| x < 3 }.all?

Mike Harris

9/27/2006 10:24:00 PM

0

Ken Kunz wrote:

>I had a scenario arise today where I needed an iterator with similar
>semantics as Enumerable#all?, but non-short-circuiting. We came up with
>a fairly elegant solution (imho), so I thought I'd be a good rubyzen
>and share :)
>
>1) First... the standard #all? (short-circuits):
>
>irb> (1..5).all? { |i| puts i; i < 3 }
>1
>2
>3
>=> false
>
>2) Non-short-circuiting version (injecting truth):
>
>irb> (1..5).inject(true) { |retval, i| puts i; retval &&= (i < 3) }
>1
>2
>3
>4
>5
>=> false
>
>3) One more way (though I like #2 better)
>
>irb(main):016:0> (1..5).partition { |i| puts i; i < 3 }.last.empty?
>1
>2
>3
>4
>5
>=> false
>
>-Ken
>
>
>
>
>
Also, with #2, obviously your way works, but the &&= isn't neccesary, a
&& has the intended effect, since the result of the block is put in the
accumulator. Again, it doesn't matter at all, I'm mostly just writing
to avoid doing work.

dblack

9/27/2006 11:33:00 PM

0

dblack

9/27/2006 11:34:00 PM

0

dblack

9/27/2006 11:35:00 PM

0

kennethkunz

9/28/2006 3:37:00 AM

0

> How about (1..5).map { |x| x < 3 }.all?

This approach is nice and concise... but I still prefer "truth
injection" for my actual code scenario. In my real code, the block is
multiple lines, and for clarity I don't love the idea of tacking a
method call on the end of a multi-line block.

Plus I just like saying "injecting truth" :)

> ... obviously your way works, but the &&= isn't neccesary ...

Thanks for the tip.

-Ken

Robert Klemme

9/28/2006 6:49:00 AM

0

Mike Harris <GENIE@prodigy.net> wrote:
> Also, with #2, obviously your way works, but the &&= isn't neccesary,
> a && has the intended effect, since the result of the block is put in
> the accumulator. Again, it doesn't matter at all, I'm mostly just
> writing to avoid doing work.

In that case order should be reversed to avoid short circuiting altogether
(in this case it does not matter as the test has no side effects, but if it
had...)

>> (1..5).inject(true) { |retval, i| puts i; i < 3 && retval}
1
2
3
4
5
=> false

Kind regards

robert


Mike Harris

9/28/2006 2:04:00 PM

0

Robert Klemme wrote:

> Mike Harris <GENIE@prodigy.net> wrote:
>
>> Also, with #2, obviously your way works, but the &&= isn't neccesary,
>> a && has the intended effect, since the result of the block is put in
>> the accumulator. Again, it doesn't matter at all, I'm mostly just
>> writing to avoid doing work.
>
>
> In that case order should be reversed to avoid short circuiting
> altogether (in this case it does not matter as the test has no side
> effects, but if it had...)
>
>>> (1..5).inject(true) { |retval, i| puts i; i < 3 && retval}
>>
> 1
> 2
> 3
> 4
> 5
> => false
>
> Kind regards
>
> robert
>
>
>
>
Very good point, neglected to think about that, glossing over the fact
that the puts executing doesn't mean the relevant expression evaluated.
With the fixed example:

irb(main):001:0> (1..5).inject(true) { |s,i| s &&= (puts i; i < 3) }
1
2
3
=> false
irb(main):002:0> (1..5).inject(true) { |s,i| s && (puts i; i < 3) }
1
2
3
=> false
irb(main):003:0> (1..5).inject(true) { |s,i| (puts i; i < 3) && s }
1
2
3
4
5
=> false

With the &&= vs && thing, I made a salient point about a bug in the
example and I was too dumb to realize it.