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

Hi, I have a question about some code. To confirm this code is working, but I need some help understanding it.
@union = @intersection = @difference = (); %count = (); foreach $element (@array1, @array2) { $count{$element}++ } foreach $element (keys %count) { push @union, $element; push @{ $count{$element} > 1 ? \@intersection : \@difference }, $eleme +nt; } "foreach $element (@array1, @array2) { $count{$element}++ }"
I understand the foreach goes through both arrays, and adds a count of each unique object in both arrays, could someone elaborate on how this works and what "$count{$element}++" means? Also the line "push @{ $count{$element} > 1 ? \@intersection : \@difference }, $element;" It appears to say if the value count it greater than one, but in intersection else put in difference? Although I dont understand why this work. where could I get some more information? Thanks in advance. Mark

Replies are listed 'Best First'.
Re: Clarification of code - find array intersection
by wind (Priest) on Mar 16, 2011 at 01:44 UTC
    Cleaning up the code for the monks:
    @union = @intersection = @difference = (); %count = (); foreach $element (@array1, @array2) { $count{$element}++ } foreach $element (keys %count) { push @union, $element; push @{ $count{$element} > 1 ? \@intersection : \@difference }, $e +lement; }
    relientmark, It would help if you read How do I post a question effectively?
      Just read, and will follow in future. Thanks mate.

        The future is now if you simply edit your original post and add the tags.

Re: Clarification of code - find array intersection
by Marshall (Canon) on Mar 16, 2011 at 04:43 UTC
    Thanks to wind the code was formatted in a way that I could understand. Look at use of "code" tags in the formatting tips...

    I have re-written this a bit...see below.

    $count{$element}++; adds 1 to the $element entry in the %count hash table. If no such entry exists at the moment, Perl creates it for you. This is called auto-vivification - the hash entry "springs into existence" with a value of 0 and it gets incremented by one.

    The other statement push @{ $count{$element} > 1 ? \@intersection : \@difference }, $element; is a rather complicated way of expressing an "if,else" statement. You can read about the ternary operator. Past that, this statement uses some tricky reference syntax that is not needed here. Do not make the mistake of assuming that fewer lines of source code means a faster program. My reformulated version will run just as fast and maybe even faster and I am sure that it will be easier for you to understand.

    Update:
    More typical code with ternary operator would be something like this: my $result = ($x > $y) ? 1: 0; This is an "if..else" statement.

    (keys %count) does not have any particular order. That is the disadvantage of a hash table - you don't get easy sequential ordered access. Perl has some very good sorting functions so that you can get the order to come out like you want, but adding that to this code seemed an over complication given that we are still working on the basics.

    #!/usr/bin/perl -w use strict; # this initialization to () is not necesssary, but ok my (@union, @intersection, @difference, %count) = (); my @array1 = (1,2,3); my @array2 = (3,4,1); foreach my $element (@array1, @array2) { $count{$element}++; #auto-vivification of a hash entry } foreach my $element (keys %count) # a print to show results so far { print "$element occured $count{$element} times\n"; } @union = keys %count; # same as the push @union, $element statement # it would be faster to have this within the # foreach loop, because calculating the keys # takes some "work", but I'm showing here # what this does. @union and keys %count are # equivalent. foreach my $element (keys %count) { if ($count{$element} > 1) #element occured more than once { push @intersection, $element; } else #element only occured once { push @difference, $element; } } print "union=@union; intersection=@intersection; difference=@differenc +e\n"; __END__ 4 occured 1 times 1 occured 2 times 3 occured 2 times 2 occured 1 times union=4 1 3 2; intersection=1 3; difference=4 2
      Cheers Marshall