Injecting truth

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

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

(1..5).all? { |i| puts i; i < 3 }

1
2
3
=> false

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

(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

Hmm, why Enumerable#all? without short circuit? If you get to a point where
the block doesnt apply, then you might aswell break.

j`ey
http://www.eachmapinject.com

路路路

On 9/27/06, Ken Kunz <kennethkunz@gmail.com> 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 :slight_smile:

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

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

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

> (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

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

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

(1..5).all? { |i| puts i; i < 3 }

1
2
3
=> false

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

(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?

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

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

(1..5).all? { |i| puts i; i < 3 }

1
2
3
=> false

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

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

Hi --

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

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

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

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

> (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

Cool. I want to play too :slight_smile:

[*1..5].map {|i| puts i; i < 3 }.all?

1
2
3
4
5
=> false

David

路路路

On Thu, 28 Sep 2006, Ken Kunz wrote:

--
                   David A. Black | dblack@wobblini.net
Author of "Ruby for Rails" [1] | Ruby/Rails training & consultancy [3]
DABlog (DAB's Weblog) [2] | Co-director, Ruby Central, Inc. [4]
[1] Ruby for Rails | [3] http://www.rubypowerandlight.com
[2] http://dablog.rubypal.com | [4] http://www.rubycentral.org

Hi --

路路路

On Thu, 28 Sep 2006, Mike Harris wrote:

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

Whoops, I didn't see that before I (re)posted it :slight_smile:

David

--
                   David A. Black | dblack@wobblini.net
Author of "Ruby for Rails" [1] | Ruby/Rails training & consultancy [3]
DABlog (DAB's Weblog) [2] | Co-director, Ruby Central, Inc. [4]
[1] Ruby for Rails | [3] http://www.rubypowerandlight.com
[2] http://dablog.rubypal.com | [4] http://www.rubycentral.org

Hi --

路路路

On Thu, 28 Sep 2006, Joey wrote:

Hmm, why Enumerable#all? without short circuit? If you get to a point where
the block doesnt apply, then you might aswell break.

The idea is that it's a case where you want the block to be executed,
unconditionally, once for every element in the array, and also want to
know whether at least one iteration returned false.

David

--
                   David A. Black | dblack@wobblini.net
Author of "Ruby for Rails" [1] | Ruby/Rails training & consultancy [3]
DABlog (DAB's Weblog) [2] | Co-director, Ruby Central, Inc. [4]
[1] Ruby for Rails | [3] http://www.rubypowerandlight.com
[2] http://dablog.rubypal.com | [4] http://www.rubycentral.org

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" :slight_smile:

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

Thanks for the tip.

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

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 <GENIE@prodigy.net> wrote:

Robert Klemme 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.

路路路

Mike Harris <GENIE@prodigy.net> wrote: