Beefy Boxes and Bandwidth Generously Provided by pair Networks
Problems? Is your data what you think it is?
 
PerlMonks  

Multiple Conditional Statements

by jdlev (Scribe)
on Sep 11, 2013 at 10:56 UTC ( #1053458=perlquestion: print w/ replies, xml ) Need Help??
jdlev has asked for the wisdom of the Perl Monks concerning the following question:

Hi again guys...got a quick, easy question.

Does perl have anything that you can use to make sure that your variable values don't match, and do it all at once? Here's an example:

if ($RB1 != $RB2 != $WR1 != $WR2 != $TE1)
What's the easiest way to make sure none of these variables match any of the others. Like $RB1 <> $RB2, $RB1 <> $TE1, $TE1 <> $WR2....well, you get the drift. Am I doomed to using 15 && Statements? :(

I love it when a program comes together - jdhannibal

Comment on Multiple Conditional Statements
Download Code
Re: Multiple Conditional Statements
by vsespb (Hermit) on Sep 11, 2013 at 11:07 UTC
    possible solution:
    use strict; use warnings; my ($x, $y, $z, $w) = (1, 2, 3, 4); my @A = sort { $a <=> $b } $x, $y, $z, $w; my $ok = 1; while (@A) { $ok = 0 if @A >= 2 && $A[0] == $A[1]; shift @A; } print $ok;
    UPD:
    fixed: sort should be numerical.
Re: Multiple Conditional Statements
by BrowserUk (Pope) on Sep 11, 2013 at 11:10 UTC

    You could use an anonymous hash:

    ( $RB1, $RB2, $WR1, $WR2, $TE1 ) = map int( rand 10 ), 1 .. 5;; print $RB1, $RB2, $WR1, $WR2, $TE1;; 3 5 5 8 7 if( keys %{ { map{ $_,$_ } $RB1, $RB2, $WR1, $WR2, $TE1 } } == 5 ) { say 'all different' } else { say 'some same' };; some same ( $RB1, $RB2, $WR1, $WR2, $TE1 ) = map int( rand 10 ), 1 .. 5;; print $RB1, $RB2, $WR1, $WR2, $TE1;; 1 8 6 7 5 if( keys %{ { map{ $_,$_ } $RB1, $RB2, $WR1, $WR2, $TE1 } } == 5 ) { say 'all different' } else { say 'some same' };; all different

    But be wary of what you mean by "different" if these can be floating point values.


    With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.
      There can be problem with string vs numeric comparison:
      use v5.10; ( $RB1, $RB2, $WR1, $WR2, $TE1 ) = (1,2, 3, "05", 5); if( keys %{ { map{ $_,$_ } $RB1, $RB2, $WR1, $WR2, $TE1 } } == 5 ) { say 'all different'; } else { say 'some same' };; prints "all different"

        Indeed.


        With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
        Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
        "Science is about questioning the status quo. Questioning authority".
        In the absence of evidence, opinion is indistinguishable from prejudice.

        For strictly numeric comparison add 0+:

        if( keys %{ { map{ 0+$_,$_ } $RB1, $RB2, $WR1, $WR2, $TE1 } } == 5 ) { + say 'all different' } else { say 'some same' };;

        With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
        Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
        "Science is about questioning the status quo. Questioning authority".
        In the absence of evidence, opinion is indistinguishable from prejudice.
Re: Multiple Conditional Statements
by Perlbotics (Abbot) on Sep 11, 2013 at 11:19 UTC

    You should introduce a test function instead of listing all combinations in the if clause. I read your condition as no duplicates allowed, so this should work:

    use strict; use warnings; use Test::More; sub all_different { my %seen; for ( @_ ) { return 0 if $seen{$_}++; } #-- duplicate found return 1; } # e.g. if ( all_different($RB1, $RB2, $WR1, $WR2, $TE1) ) { ... is( all_different( 1,2,3,4,5 ), 1 , "all different"); is( all_different( 1,1,3,4,5 ), 0 , "some duplicates"); is( all_different(), 1 , "empty paramlist"); done_testing;

    Perhaps you can also use uniq() from List::MoreUtils?

    Update: In response to vsespb's comment below - the OP didn't specify if e.g. 05.0 is identical to 5 or not - probably yes, so numification is advised. However, as shown below, sanitizing input or creating a specialised all_different_nums() sub can be done by the OP if necessary. Only the OP knows, what is equal in his/her given context. I.e., floats might need normalisation using sprintf... we don't know (yet).

    Maybe this one is more robust?

    use strict; use warnings; use Scalar::Util qw(looks_like_number); use Test::More; sub all_different { my %seen; for ( @_ ) { my $norm_val = looks_like_number( $_ ) ? 0+$_ : $_; return 0 if $seen{$norm_val}++; #-- duplicate found } return 1; } # e.g. if ( all_different($RB1, $RB2, $WR1, $WR2, $TE1) ) { ... is( all_different( 1,2,3,4,5 ), 1 , "all different (num)"); is( all_different( 1,1,3,4,5 ), 0 , "some duplicates (num)"); is( all_different( qw(a b 8) ), 1 , "all different (str)"); is( all_different( qw(a a 8) ), 0 , "some duplicates (str)"); is( all_different( qw(5 05.0 8) ), 0 , "some duplicates (mixed)"); is( all_different(), 1 , "empty paramlist"); done_testing;

      Same problem with your example and with uniq() - string vs numeric comparison. Can be worked around by numifying data:
      use strict; use warnings; use Test::More; sub all_different { my %seen; for ( @_ ) { return 0 if $seen{$_}++; } #-- duplicate found return 1; } # e.g. if ( all_different($RB1, $RB2, $WR1, $WR2, $TE1) ) { ... is( all_different( 1,2,3,4,5 ), 1 , "all different"); is( all_different( 1,2,3,"05",5 ), 0 , "some duplicates with different + string"); is( all_different( map { $_+0 } 1,2,3,"05",5 ), 0 , "some duplicates w +ith different strings numified"); is( all_different( 1,1,3,4,5 ), 0 , "some duplicates"); is( all_different(), 1 , "empty paramlist"); done_testing;
      result:
      ok 1 - all different not ok 2 - some duplicates with different string # Failed test 'some duplicates with different string' # at 3.pl line 17. # got: '1' # expected: '0' ok 3 - some duplicates with different strings numified ok 4 - some duplicates ok 5 - empty paramlist 1..5
      the OP didn't specify if e.g. 05.0 is identical to 5 or not - probably yes
      Well, OP specified "!=" operator in original post.
      However, as shown below, sanitizing input
      In general case, programmer cannot control if his data is numified or no. So I don't think it's really about "sanitizing".
      floats might need normalisation using sprintf...
      In general case, normalization for floats won't work well, example:
      perl -e 'my ($a, $b) = (0.45000001, 0.4499999); print sprintf ("%0.1f +%0.1f %f", $a, $b, $a-$b )'
      prints 0.5, 0.4 and 0.000000

      My example Re: Multiple Conditional Statements can be fixed to work with floats (but I admit it's slow).
      UPD: fixed float example
Re: Multiple Conditional Statements
by BillKSmith (Chaplain) on Sep 11, 2013 at 15:01 UTC
    If you like a more direct approach,
    use strict; use warnings; use List::MoreUtils qw(any); my ($RB1, $RB2) = (1,2); my ($WR1, $WR2) = (3,4); my $TE1 = 1; my $match; my @a = \($RB1, $RB2, $WR1, $WR2, $TE1); for my $i (0..3){ $match |= any {${$a[$i]} == $$_} @a[$i+1 .. 4]; } print "No " if !$match; print "match\n";
    You could use grep in place of any (List::MoreUtils), but the name 'any' seems to convey the intent better.
    Bill
      If you like a more direct approach,

      That's a perfectly valid approach, but how is it "more direct"? (And "more direct" that what for that matter?)

      You have:

      1. An auxiliary boolean variable;
      2. An auxiliary array (... of references which have to be taken);
      3. Two nested loops;
      4. A callback function (from a module);
      5. An array slice;
      6. n(n+1) dereferences;
      7. n(n+1)/2 comparisons;
      8. And it doesn't even short-circuit if the first two variables compared are the same.

      That's the strangest definition of "more direct" I can think of :)


      With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
      Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
      "Science is about questioning the status quo. Questioning authority".
      In the absence of evidence, opinion is indistinguishable from prejudice.
        Of course I agree with all your arguments. All I meant to imply was that it directly compares the variables in question (not copies) and with very little source code. I find it very easy to understand. In general, that should trump issues of speed, memory, or namespace.
        Bill
Re: Multiple Conditional Statements
by hdb (Parson) on Sep 11, 2013 at 15:44 UTC

    ...and a recursive option with error tolerant comparison...

    use strict; use warnings; my $eps = 1e-10; sub distinct { return 1 if @_<2; # lists of 1 or empty lists never have dupli +cates my $first = shift; for( @_ ) { return 0 if abs($first - $_)<$eps; } return distinct( @_ ); } my @n = ( 1, 2, 3, 4, 4 ); print distinct( @n );
Re: Multiple Conditional Statements
by sundialsvc4 (Monsignor) on Sep 11, 2013 at 15:57 UTC

    Anytime I see repeating-variable names like $RBn, I immediately think that $RB should instead be, say, a list with n elements in it.   And in this case, that maybe the root variable should be a hash with keys such as 'RB', 'TE', 'WR'.

    When looking for dupes, and especially if the values are scalar or string, a hash can come in handy:   you jump-out as soon as anything exists(), viz ... for illustration only ...

    my $dupes = {}; for my $k (qw/RB TE WR/) { for my $n (qw/1 2 3 4 5/) { $n = $my_data->{$k}{$v}; return 'DUPLICATE FOUND' if exists($dupes->{$n}); $dupes->{$n} = 1; // DON'T CARE ANY VALUE WILL DO } } return 'NO DUPLICATES';

    This example illustrates the use of a hash ($my_data) to store the values, and of a hash ($dupes) to find duplicates.   The technique would not work so-good if the values being sought were floating point.)

Re: Multiple Conditional Statements
by TJPride (Pilgrim) on Sep 11, 2013 at 19:26 UTC
    The best solution to finding dupes is almost always a hash.
    use strict; use warnings; my ($RB1, $RB2, $WR1, $WR2, $TE1) = (1, 2, 3, 1, 4); { my %lookup; for ($RB1, $RB2, $WR1, $WR2, $TE1) { if ($lookup{$_}++) { print "Dupe $_\n"; last; } }}
      This should work as the original values are numbers, but this is inefficient as the numeric values have to be stringified to be put as keys the hash. And the hash construction itself counts too.
        That only matters if you are working with literally millions of items, and the alternative is far worse. Constructing a hash is more efficient than, say, sorting a large list of items.
Re: Multiple Conditional Statements
by boftx (Chaplain) on Sep 12, 2013 at 00:23 UTC

    Is there any way to upvote the entire thread as an excellent example of TIMTOWTDI in action? The only thing missing is a keg to help lubricate the thought processes. :)

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://1053458]
Front-paged by Corion
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others taking refuge in the Monastery: (5)
As of 2014-08-02 04:39 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    Who would be the most fun to work for?















    Results (54 votes), past polls