http://www.perlmonks.org?node_id=502182


in reply to One out of three ain't bad

Avoid the obfuscating punctuation:

if( 1 == grep $_, $x, $y, $z )

Or, using a more versatile trick:

if( 1 == !!$x + !!$y + !!$z )

But note that some will kvetch that the fact of !0 == 1 is "not defined" in Perl. But that ship has already sailed; practicality actually prevents Perl from changing the value of "true" to something other than 1, even if this property was intentionally left undefined.

- tye        

Replies are listed 'Best First'.
Re^2: One out of three ain't bad (order)
by ph713 (Pilgrim) on Oct 22, 2005 at 08:42 UTC
    I like this !! based solution the best. It's the most logical way to solve the problem - convert the arguments to boolean truth values, then sum them. You could do it for an arbitrarily long list of variables with:
    use List::Util qw( sum ); if( 1 == sum( map { !!$_ } @inputs) ) { ... }

      As long as you're going to go through the same code path for each element in the array anyway, why not de-obfuscate that a bit and use the ternary operator?

      if (1 == sum( map { $_ ? 1 : 0 } @inputs ))
      While tye may be right that, in practice, Perl can't change the value of !0, I just don't like relying on obscure implementation details when clear, well-defined implementation details are available to me to accomplish the same thing in a readable, understandable, and maintainable manner.

        Why are you using sum instead of grep here? If you are summing 1 and 0 then the sum will always be the same as the grep answer. For what it's worth I woul disagree that ($_ ? 1 : 0) is clearer in anyway than !!$_. To me the !! version yells bool, while I had to read the ?: version twice before comprehension came. That might be in part because Perl6's new bool context (don't shoot me if that isn't the right wording) lets you ask for a true/false value explicity so thats what I would expext !! to do.


        ___________
        Eric Hodges
Re^2: One out of three ain't bad (order)
by Dr. Mu (Hermit) on Oct 23, 2005 at 04:21 UTC
    Or, shorter:

    if (2 == !$x + !$y + !$z) {

      Which seems to work right now, since you've seen the progression of what came before. But in 2 months, I can imagine you thinking, "Now why in the world is there a two in there... I must want two of them to be true" on your first look while skimming your code.

          -Bryan

        True enough. I suppose what's lacking is a commonly-accepted idiom for Boolean conversions. We have 0+ for numeric conversions; so perhaps !! wasn't so bad after all, even though two operations are implied (unless the compiler optimizes them out). 0|| and 1&& would also work.