dajoto
dajoto

Reputation: 460

In Perl, how do I check to see if an array matches a value listed at least once within it's contents?

I've never really worked with Perl before (avoided it where I could) and so my knowledge is sparse on the topic.

I know the script I am looking at has an array of ProductID values in @::s_Ship_sShipProducts.

I was attempting to see if any of the ProductIDs in the array began with either B or S and execute a function if so, else do another function. But what I ended up with was for each ProductID do the statement. This is what I (admittedly salvaged) had.

my $i;
for $i (0 .. $#::s_Ship_sShipProducts) # for each product
    if  ($::s_Ship_sShipProducts[$i] =~ /^(B|S)/) # Determine if B or S product
        {
        if (defined $phashBandDefinition->{'FreeOver'} && CalculatePrice() > 250)
        {$nCost = 0;}
        }
    else    {
        if (defined $phashBandDefinition->{'FreeOver'} && CalculatePrice() > $phashBandDefinition->{'FreeOver'})
        {$nCost = 0;}
        }

How could I change this so that the array was inspected to see if any ProductID was true and return true, or false if nothing matched? Then execute the appropriate function based on true or false? I have done some reading, but am still in the dark. Thanks for your time.

Upvotes: 1

Views: 145

Answers (2)

DVK
DVK

Reputation: 129403

If the array is not too big (or you don't care THAT much about performance), you can check if there are any matching values via grep:

if (my @matching_elements = grep { /^(B|S)/ } @::s_Ship_sShipProducts) {
   # Better yet use /^[BS]/ expression - more idiomatic/readable
   print "Found B/S\n";
} else {
   print "NOT Found B/S\n";
}

When done, @matching_elements would contain a list of matching IDs.

In the rare case when the array IS too big to scan through entirely and you only need to find the first occurance, you can use any of the array search optimization strategies discussed in binary search in an array in Perl


By the way, your approach to search works perfectly fine, you merely need to quit the loop once you found - and to boot, is one of those optimized approaches shown in the list above:

for my $i (0 .. $#::s_Ship_sShipProducts) # for each product
    if  ($::s_Ship_sShipProducts[$i] =~ /^[BS]/) {  # Determine if B or S product
        # Execute your logic here
        last; # Found, get out of the loop.
    } 
}

NOTE: In Perl 5.10 and above, you can - instead of grep - use a so-called "smart match" operator ~~:

if (@::s_Ship_sShipProducts ~~ /^(B|S)/) {
    # Your logic
}

Upvotes: 6

jiggy
jiggy

Reputation: 3826

I'm not quite sure if I'm following your question, but I think you are looking for grep.

my @matched_products = grep(/^(B|S)/,@::s_Ship_sShipProducts);

Upvotes: 2

Related Questions