use strict;
use warnings;

my @ArrayA = qw(1 3 5 6 7 8 a b c d e f g h i j k l m n o p q r s t u v w x z);
my @ArrayB = qw(2 3 5 7 9 x z n r t u v A B C D);
my (@Aonly, @Bonly, @Both);
my ($Diff, $Union);

compare(\@ArrayA, \@ArrayB, \@Aonly, \@Bonly, \@Both);
print "A:     @ArrayA\n";
print "B:     @ArrayB\n\n";
print "Both:  @Both\n";
print "Aonly: @Aonly\n";
print "Bonly: @Bonly\n";

$Diff = difference(\@ArrayA, \@ArrayB);
print "Diff:  @{$Diff}\n";

$Union = union(\@ArrayA, \@ArrayB);
print "Union: @{$Union}\n";


sub difference # A, B
  {
  my @a = @{$_[0]};
  my @b = @{$_[1]};

  my @diff = ();
  my %count = ();

  # put all items in hash table 
  # Values: 1: in a, 2: in b, 3: in both
  foreach my $e (@a) 
    { $count{$e} = 1; } 
  foreach my $e (@b) 
    { $count{$e} += 2; } 

  foreach my $e (@a, @b) 
    { push @diff, $e if $count{$e} != 3; } 
  return (\@diff); 
  }

sub compare # A, B, Aonly, Bonly, Both
  {
  my @a = @{$_[0]};
  my @b = @{$_[1]};

  @{$_[2]} = @{$_[3]} = @{$_[4]} = ();
  my %count = ();

  # put all items in hash table 
  # Values: 1: in a, 2: in b, 3: in both
  foreach my $e (@a) 
    { $count{$e} = 1; } 
  foreach my $e (@b) 
    { $count{$e} += 2; } 

  foreach my $e (@a) # A only 
    { push(@{$_[2]}, $e) if $count{$e} == 1; }

  foreach my $e (@b) # B only
    { push(@{$_[3]}, $e) if $count{$e} == 2; }

  foreach my $e (@a) 
    { push (@{$_[4]}, $e) if $count{$e} == 3; } 
  }

sub union # A, B
  {
  my @a = @{$_[0]};
  my @b = @{$_[1]};

  my @union = ();
  my %count = ();

  # put all items in hash table 
  # Values: 1: in a, 2: in b, 3: in both
  foreach my $e (@a) 
    { $count{$e} = 1; } 
  foreach my $e (@b) 
    { $count{$e} += 2; } 

  foreach my $e (@a) 
    { push(@union, $e) unless $count{$e} == 3; }
  foreach my $e (@b) 
    { push(@union, $e); }

  return (\@union); 
  }
