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

I have two arrays, @allnames and @somenames. I want to check each element of @allnames to see if that element exists in @somenames. If the element does exist then I would like to increment $count. I tried this which I saw online somewhere
for (@allnames) { if (@somenames){ $count++; } }
but it does not work for me. Any suggestions or advice is appreciated. TJ.

Replies are listed 'Best First'.
Re: check all elements of an array against another array...
by davido (Cardinal) on Jul 01, 2014 at 04:40 UTC

    The bug in your script seems to stem from a misunderstanding of what happens when you evaluate an array in Boolean context. if(@array) {... doesn't test every single element against some implicit variable such as $_. All it does, is evaluate the array in scalar context, which returns the number of elements in the array. Therefore, if there are zero elements, the conditional will be false. If there are more than zero elements, it will be true.

    Here are a couple of ways to do it. In terms of computational complexity, this first one is a linear growth-rate solution:

    my $count = do { my %seen; @seen{@somenames} = (); my $c; foreach my $name ( @allnames ) { $c++ if exists $seen{$name}; } $c; };

    This is a quadratic solution:

    my $count; foreach my $name (@allnames) { $count++ if grep { $_ eq $name } @somenames; }

    The first solution trades memory for computational efficiency; its rate of growth in memory requirements is linear, tied to the growth of @somenames. Its rate of growth in computational complexity is tied to the growth of @allnames+@somenames. Update: I've limited the duration of the memory requirement to a narrow scope; in theory Perl could reuse the memory consumed by %seen since it's falling out of scope at the end of the do{} block.

    The second solution has constant memory requirements, but must run through "@somenames" one time for every element in @allnames. This could become very slow very fast, if the arrays grow. The second solution could, in principle, be improved upon by using List::Util::any. Unfortunately (or fortunately, depending on how you look at it), grep is highly optimized in ways that seem to be unavailable to XSUBS, so 'any' it often not a performance win, though its semantic purity may still make it a good alternative.


    Dave

      TYVM for the advice and extra information about what Perl is doing behind the scenes. I will try both and see how they work for my application. Thanks again for the great reply! TJ.
Re: check all elements of an array against another array...
by Anonymous Monk on Jul 01, 2014 at 04:43 UTC

    So it sounds like you want the intersection of two arrays - see for example How can I find the union/difference/intersection of two arrays?. In the first example there, you can get your count via my $count = @female_simpsons;, or more directly by my $count = grep ... - note however this might not be the best approach if your arrays are large because it will consume quite a bit of memory.

Re: check all elements of an array against another array...
by hippo (Archbishop) on Jul 01, 2014 at 09:21 UTC