Beefy Boxes and Bandwidth Generously Provided by pair Networks
We don't bite newbies here... much
 
PerlMonks  

Check multiple array elements for a single condition

by Anonymous Monk
on Aug 25, 2016 at 10:38 UTC ( [id://1170403]=perlquestion: print w/replies, xml ) Need Help??

Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

Just a quick question - is there a shorthand form of this:

if ($array[0] == 0 && $array[1] == 0)

A statement that would check both elements [0] and 1 for the condition ==0 without having to repeat the statement?

Replies are listed 'Best First'.
Re: Check multiple array elements for a single condition
by hippo (Bishop) on Aug 25, 2016 at 10:50 UTC

    List::Util's all will do that.

    #!/usr/bin/env perl use strict; use warnings; use List::Util 'all'; print "a yes\n" if all { $_ == 0 } (0, 0, 0); print "b no\n" unless all { $_ == 0 } (0, 1, 0);
Re: Check multiple array elements for a single condition
by TheDamian (Vicar) on Aug 25, 2016 at 12:03 UTC
    You could also use the Smart::Match module with smartmatching:
    use Smart::Match 'all'; if ( 0 ~~ all(@array[0,1]) ) { say 'matched'; }
    Or you could do exactly the same thing "natively", in Perl 6:
    if @array[0 & 1] == 0 { say 'matched'; }
    Damian
      Just thinking - what about:

      if (!(@array[0]+@array[1]))

      Nick
        if (!(@array[0]]+@array[1]))

        False positive if $array[0] == -$array[1].

        Alexander

        --
        Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so". ;-)

        Try if (!(@array[0] | @array[1])) instead. (For reasons afoken stated.)

      Isn't Smart Match deprecated?
Re: Check multiple array elements for a single condition
by Discipulus (Canon) on Aug 25, 2016 at 11:07 UTC
    you can use the smartmatch operator but is not a big improvement:
    perl -mstrict -we "my @arr=(1,2,2);print 'both' if [2,2] ~~ @arr[1,2]" both
    or if you just want 2 casual elements to be equal to 2 you can chek the lenght of the list returned by grep
    perl -mstrict -we "my @arr=(1,2,2);print 'exactly two' if (grep{$_==2} +@arr) == 2" exactly two

    L*

    There are no rules, there are no thumbs..
    Reinvent the wheel, then learn The Wheel; may be one day you reinvent one of THE WHEELS.
Re: Check multiple array elements for a single condition
by Marshall (Canon) on Aug 25, 2016 at 19:38 UTC
    As a contrary opinion, I think your code is fine. It is very clear, short and will execute very efficiently. I see no need to make it "shorter". Any shorter high level version of this will code to the same thing at lower levels. You are fine with this.
Re: Check multiple array elements for a single condition
by afoken (Chancellor) on Aug 26, 2016 at 06:51 UTC

    Generalised for arrays of any size:

    Checking if all elements of an array (all operator) match the same condition is equivalent to checking if at least one element (any operator) does not match the negated condition (De Morgan's laws).

    grep can be used as an any operator, by checking the size of the returned array.

    In code:

    if (!grep { $_ != 0 } @array) { print "No array element is non-zero, so:\n"; print "All array elements are zero, or the array is empty\n"; }

    Or a little bit more perlish:

    unless (grep { $_ != 0 } @array) { print "No array element is non-zero, so:\n"; print "All array elements are zero, or the array is empty\n"; }

    Note that grep is less efficient in this case than a specialised any function, because grep always tests the entire array, whereas the any function can stop at the first match. Both List::Util and List::MoreUtils offer an optimized any function.

    Those modules also offer an optimized all function that stops after the first mismatch. They also offer the negated functions none and notall, and the function one that searches for exactly one match.


    Could we patch Perl to implement grep as any (i.e. stop at the first match) if grep is used in a boolean context? Probably, but it would break code that abuses grep for its side effects, i.e. code that expects grep to always evaluate the block/expression for all array elements.

    Alexander

    --
    Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so". ;-)
Re: Check multiple array elements for a single condition
by stevieb (Canon) on Sep 11, 2016 at 15:07 UTC

    Another example using grep. This one isn't much shorter, but where it'll help is if you have to check more elements; simply add the element number to the array slice, and update the equal-to count number.

    if ((grep /^0$/, @array[0,1]) == 2){ say "both are zero"; }
      add the element number to the array slice, and update the equal-to count number.

      Whenever a single change requires two (or more) synchronised updates to the code, this is a bug waiting to happen.

      In this case, we can take advantage of the fact that “all x are y” is logically equivalent to “it is not the case that any x is not y.” That is, we can eliminate the duplication by negating both the condition and the if statement:

      use strict; use warnings; my @array = qw( 0 0 7 abc 0 ); for my $i ([0, 1, 4], [0, 1, 3, 4], [1], [], [2]) { print "(@array[ @$i ]): "; if (grep !/^0$/, @array[ @$i ]) # !/^0$/ would be better as $_ ne + '0' { print "not all are zero\n"; } else { print "all are zero\n"; } }

      Output:

      1:40 >perl 1692_SoPW.pl (0 0 0): all are zero (0 0 abc 0): not all are zero (0): all are zero (): all are zero (7): not all are zero 1:40 >

      Hope that helps,

      Athanasius <°(((><contra mundum Iustus alius egestas vitae, eros Piratica,

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others making s'mores by the fire in the courtyard of the Monastery: (3)
As of 2024-04-19 01:35 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found