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

I am trying to write a script that will compare two arrays and create a third array that contains any elements that are not shared by both arrays. For example:

@Array1 = (2, 4, 6, 8, 10); @Array2 = (1, 2, 3, 4, 5);

These two arrays would be compared and this array would be created:

@Array3 = (1, 3, 5, 6, 8, 10);

I'm sure I could come up with a sloppy solution using a couple foreach loops and conditionals, but I thought there may be an easier way to do this.

Replies are listed 'Best First'.
Re: Comparing Two Arrays
by kvale (Monsignor) on Feb 23, 2005 at 22:09 UTC
    If your arrays are in fact representing sets, i.e., no repeated elements, Set::Scalar has what you need:
    use Set::Scalar; $s = Set::Scalar->new( 2, 4, 6, 8, 10); $t = Set::Scalar->new( 1, 2, 3, 4, 5); $d = $s->symmetric_difference($t); print $d, "\n";

    -Mark

      That did exactly what I needed, Mark. Thanks for the quick reply.
Re: Comparing Two Arrays
by dragonchild (Archbishop) on Feb 23, 2005 at 22:10 UTC
    To rephrase, you have two sets of data and you want to find the union - intersection. In other words, take elements that appear in either set and get rid of the elements that appear in only one set.

    Using Set::Scalar, I would solve your problem as so:

    use strict; use Set::Scalar; my $set1 = Set::Scalar->new( @array1 ); my $set2 = Set::Scalar->new( @array2 ); my $set3 = $set1->difference( $set2 )->union( $set2->difference( $set1 + ) ); my @array3 = $set3->members;

    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.

      I noticed Mark's suggestion first, which was very similar to yours. I was working along happily, but then I got stuck because I needed the output as an array--not a scalar. Your reply helped me achieve the output I needed. $set3->members worked perfectly! Thanks for your help!

      Title edit by tye from just "Thanks"

Re: Comparing Two Arrays
by dn (Acolyte) on Feb 23, 2005 at 22:33 UTC
    Here's a solution from the Perl Cookbook which gets the union, intersection, and symmetric difference.
    my @a = (2,4,6,8,10); my @b = (1,2,3,4,5); my @isect = my @diff = my @union = (); my %count; $count{$_}++ for (@a, @b); @union = keys %count; for (keys %count) { push @{$count{$_} == 2 ? \@isect : \@diff}, $_; }
      Just a tip, you may wish to invert your ?: clause if you ever wish to handle n cases.

      push @{$count{$_} != 1 ? \@diff : \@isec}, $_;

      ----
      Give me strength for today.. I will not talk it away..
      Just for a moment.. It will burn through the clouds.. and shine down on me.

Re: Comparing Two Arrays
by ikegami (Patriarch) on Feb 23, 2005 at 22:39 UTC
    @Array1 = (2, 4, 6, 8, 10); @Array2 = (1, 2, 3, 4, 5); undef $Array1{$_} foreach @Array1; undef $Array2{$_} foreach @Array2; foreach (@Array1) { if (!exists($Array2{$_})) { push(@Array3, $_); } } foreach (@Array2) { if (!exists($Array1{$_})) { push(@Array3, $_); } } $,=", "; $\="\n"; print(@Array3); # 6, 8, 10, 1, 3, 5

    This can be optimised if the values are known to be sorted.

Re: Comparing Two Arrays
by kutsu (Priest) on Feb 23, 2005 at 22:09 UTC
      A great link ...that doesn't answer the question.

        It answer the question "how to get a unique set of the values of two arrays". I did not realize he wanted the symmetric difference between two sets (and didn't know what symmetric difference was until I looked it up) and forgot that the heading has changed to How can I remove duplicate elements from a list or array, in 5.8.* at least. I esp. thought point E would be helpful and should point out that perldoc -q 'symmetric difference' will give an example of that too, though I prefer the module now that I see this. I'll leave it there though as it many answer later questions.

        "Cogito cogito ergo cogito sum - I think that I think, therefore I think that I am." Ambrose Bierce