Beefy Boxes and Bandwidth Generously Provided by pair Networks
Come for the quick hacks, stay for the epiphanies.
 
PerlMonks  

Compare all array values without a loop

by Anonymous Monk
on Oct 19, 2004 at 14:15 UTC ( [id://400532]=perlquestion: print w/replies, xml ) Need Help??

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

if I have
$foobar='D';
@array=('A', 'B', 'C', 'D');

is there a way I can compare $foobar to every @array value in a single if statement? without a loop?

for example...

if($foobar eq @array[0 to 3]{ #yadda yadda }

I dont think that works, but it might help describe what Im saying better... thanks

Replies are listed 'Best First'.
Re: Compare all array values without a loop
by edan (Curate) on Oct 19, 2004 at 14:19 UTC
    if ( grep { $_ eq $foobar} @array ) { }

    Update: Use the above code if you really want to compare all array values (which is what you said). If you really want to just know if the value is in the array (and then stop searching), you might try the following, which might perform better in certain situations:

    use List::Util qw(first); if ( first { $_ eq $foobar } @array ) { }
    --
    edan

      I believe the original poster wanted to know whether every value in the array equalled the given value, not whether it occurred once. Perhaps he could clarify. (Of course, now both answers are available in replies.)
      rjbs

        I think it's not very clear from the original post, but my assumption was that the poster was looking to solve the "is this value in this list" problem, so that's what I solved. I think this is a far more common problem than "is this list composed exclusively of this value"... don't you?

        --
        edan

      Assuming that $foobar isn't undefined you should have a definedness check for the return value of first too. $foobar may be 0 or "".

      If undef is allowed as comparision value, use

      defined( defined $foobar ? first { $_ eq $foobar } @array : first { not defined $array[$_] } 0 .. $#array )
      instead.

      ihb

      See perltoc if you don't know which perldoc to read!
      Read argumentation in its context!

      Quantum::Superpositions has any() and all() operations that may fit the bill. I don't know how the performance compares to List::Util and don't have time to check. Its just a fun module.
      yay, thank you!
Re: Compare all array values without a loop
by dragonchild (Archbishop) on Oct 19, 2004 at 14:25 UTC
    use Quantum::Superpositions; my $foobar = 'D'; my @array = 'A' .. 'D'; if ($foobar eq any( @array ) ) { print "Yay!\n"; } else { print "Boo\n"; }

    In Perl6, the any and all functions will be keywords.

    Being right, does not endow the right to be rude; politeness costs nothing.
    Being unknowing, is not the same as being stupid.
    Expressing a contrary opinion, whether to the individual or the group, is more often a sign of deeper thought than of cantankerous belligerence.
    Do not mistake your goals as the only goals; your opinion as the only opinion; your confidence as correctness. Saying you know better is not the same as explaining you know better.

Re: Compare all array values without a loop
by fergal (Chaplain) on Oct 19, 2004 at 14:28 UTC
    If you're basically looking for a quick Set membership test then using a hash rather than an array coould help.
    my %hash = ('a' => undef, 'b' => undef, 'c' => undef, 'd' => undef); if (exists $hash{'a'}) { # yadda yadda }
    Setting up the hash can be made a bit neater once you know what a hash slice is
    my %hash; @hash{'a', 'b', 'c', 'd'} = ();
    If your set of elements is going to be large and you're going to be checking frequently then a hash will be much quicker than anything that searches an array. Inserting and removing elements is also quick and doesn't have a problem with duplicates like an array could.

    You could also do a cpan search for "set" and use one of the modules there, some of them would be even faster and than hashes I think.

Re: Compare all array values without a loop
by rjbs (Pilgrim) on Oct 19, 2004 at 14:22 UTC
    if (grep({ $_ eq $foobar } @array) == @array) { ... }
    "If the number of elements equal to $foobar is the same as the number of elements in the array..." or
    unless (grep { $_ ne $foobar} @array) { ... }
    "Unless you find an element that is not equal to foobar..."

    Of course, these are both loops of a kind.
    rjbs
Re: Compare all array values without a loop
by radiantmatrix (Parson) on Oct 19, 2004 at 14:35 UTC

    You could join the array into a scalar with an unusual character as a separator, then use a match.

    $foobar='D'; $sep = chr(1); @array = ('A','B','C','D'); if (($sep.join($sep,@array).$sep) =~ m/$sep$foobar$sep/) { print "Found a $foobar in \@array!"; }

    The $sep on either side of the join() ensures that any potential match will begin and end with chr(1). You can pick other separator characters, as long as you can be sure they will not exist in your array (chr(1) is a pretty unlikely thing to find).

    Of course, it would be better to use hash-keys if you can...

    $foobar='D'; %hash = ( 'A' => undef, 'B' => undef, 'C' => undef, 'D' => undef ); print "Found a $foobar in \%hash" if exists $hash{$foobar};

    If you're avoiding multiple loop passes for performance, then you could use a one-time loop to convert the array to a hash:

    @array = ('A','B','C','D'); for (@array) { $hash{$_} = undef; } #now we have the same hash as in the previous example. #so, you can do this repeatedly with out a hit: $foo = 'D'; if (exists $hash{$foo}) { print "There was a $foo in the array\n"; }
    radiantmatrix
    require General::Disclaimer;
    "Users are evil. All users are evil. Do not trust them. Perl specifically offers the -T switch because it knows users are evil." - japhy

      Instead of

      @array = ('A','B','C','D'); for (@array) { $hash{$_} = undef; }
      you can use
      my @array = qw/A B C D/; my %hash; @hash{@array} = ();

Re: Compare all array values without a loop
by si_lence (Deacon) on Oct 19, 2004 at 14:25 UTC
    Hi,
    You can use grep for it.
    This uses an implicit loop, but it is quite close to
    the syntax you suggest:
    my $foobar='D'; my @array=('A', 'B', 'C', 'D'); if ( grep {$_ eq $foobar } @array ) { #yadda yadda };

    si_lence
Re: Compare all array values without a loop
by Random_Walk (Prior) on Oct 19, 2004 at 15:54 UTC

    Just for fun here is an evil eval way to do it without a loop.

    @a=('A', 'B', 'C', 'D'); $b='D'; if (eval "if(\$b eq \"".(join"\"){return 1}if(\$b eq \"",@a)."\"){retu +rn 1}") { Print "It was there\n" }

    Cheers,
    R.

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others avoiding work at the Monastery: (7)
As of 2024-03-19 09:51 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found