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

Hi Monks
How do I find out if an element exists in a normal array?
I have a normal array (@perf_array) and I am comparing it to the values of a hash array (%values). If a value from the normal array matchs any value in the hash array I parse out information from the normal array and set it as the value in another hash array with the matched value as its corresponding key. If any value in the hash array does not exist in the normal array I want to put the value in the hash array as a key value with 0 as its corresponding value
Hope the above makes sence
I am having trouble doing this
Hope you can help
Here is my code
... code here populates normal array (@perf_array) # put the elements into a hash array for (my $k = 0; $k <= $#perf_array; $k++) { while( my ($oid, $perf) = each %values ) { if ($perf_array[$k] =~ /.*\d+\s+$perf.*/) { $perf_hash{$perf} = $perf_array[$k]; $perf_hash{$perf} =~ s/\*\s+(\d+)\s+$perf/$1/eg; $perf_hash{$perf} =~ s/\s*$//g; chomp $perf_hash{$perf}; } } } for (my $l = 0; $l <= $#perf_array; $l++) { $perf_array[$l] =~ s/\*\s+\d+\s+(.*)/$1/eg; $perf_array[$l] =~ s/\s*$//g; chomp $perf_array[$l]; while( my ($oid1, $perf1) = each %values ) { if ( $perf1 != /$perf_array[$l]/ ) { $perf_hash{$perf1} = "0"; print "$perf1 not found; set to $perf_hash{$perf1}\n"; } } }
Thanks in advance

Replies are listed 'Best First'.
Re: normal array exists question
by Limbic~Region (Chancellor) on Jul 21, 2004 at 18:09 UTC
    Anonymous Monk,
    I wrote a tutorial on this very topic. In your case you want to loop through the hash keys and probably use List::Util's first to determine presense in the array.
    for my $key ( keys %hash ) { if ( first { $_ eq $key } @array ) { # match logic } else { # no match logic } }

    Cheers - L~R

      Question: the List::Utils first, does do a linear scan for the first element that matches?
        JanneVee,
        The tutorial covers a bit of this, but I will go into more depth here. List::Util's first is designed to generic and portable. It is prototyped to $@ where the first argument is the code reference that will be applied to the remaining items in the list. It starts at the beginning and returns as soon as the code ref evaluates to true. This does not need to be an exact match as you could use a regex in block for instance. It does have a couple of issues with regards to efficiency.
        • It does not provide ability to pass by reference so the @_ stack of aliases has to be generated. This can be costly on large lists
        • The code reference has to be dereferenced for each item in the list until a match is found.
        Now you can roll your own to be more efficient but that defeats the purpose of having portable re-useable code. Additionally, shaving a second or two off of run time is seldom worth the programmer time required to achieve it.

        Cheers - L~R

      that worked great
      thanks for your help
Re: normal array exists question
by ysth (Canon) on Jul 21, 2004 at 18:53 UTC
    Not completely sure I understood the question, and the sample code does a lot stuff that it's hard to figure out the purpose of. Ignoring the code, and just looking at your question, I think you can do (untested):

    my %out_hash = (); @out_hash{@in_array, keys %in_hash} = (("0") x @in_array, values %in_h +ash);

    BTW, a "normal array" is always just called an array. A "hash array" is usually called just a hash, but sometimes is called an associative array.

    The aboove works using a "hash slice". This looks like @hash{LIST}, and results in a list (which can be assigned to) of the values in %hash for each key in LIST. It also uses the x operator to make a list of scalar(@in_array) "0"'s.

    So the assignment will initially set $out_hash{key} to "0", for each key in @in_array, then set $out_hash{key} to $in_hash{key} for each key in %in_hash.

    Update: the above is not likely to be useful to you. I misinterpreted your "match" to mean "eq", instead of a regex match. It would be helpful if you would annotate the sample code to show which parts do and which parts don't work as you expect. Would I be correct in guessing it is just the final if statement that doesn't do what you want? I suspect you meant !~, not != there, but even that won't do what you want. You have to loop over all the keys seeing if they do match.

    Update: removed extra )

Re: normal array exists question
by JanneVee (Friar) on Jul 21, 2004 at 18:17 UTC
    style remark: May I suggest a foreach statement instead of a regular for loop. To make the code a little more readable.