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

Hey Monks
I'm trying to print and then remove duplicates from two arrays. By this I mean if the array 1 contains the number 3 and the array 2 contains the number 3 also. Then this would be printed and the numbers 3 removed from each array.

#!/usr/perl use strict; my @array1 = (0,1,2,3,4,5,6,7,8,9); my @array2 = (0,1,4,); my $num = "3"; my $array1size = @array1; my $array2size = @array2; for (my $count1=0;$count1 < $array1size;$count1++){ for (my $count2=0;$count2 < $array2size;$count2++){ if ($array1[$count1] == $array2[$count2]){ print $array1[$count1] . " is present in array1 and it (" . $a +rray2[$count2] . ") is also present in array2!\n"; splice (@array1, $count1, 1); splice (@array2, $count2, 1); } } }

Any idea why this isn't working. My expected output is

O is present in array1 and it(0) is also present in array2! 1 is present in array1 and it(1) is also present in array2! 4 is present in array1 and it(4) is also present in array2!

Thanks

j o h n i r l .

Sum day soon I'Il lern how 2 spelI (nad tYpe)

Replies are listed 'Best First'.
Re: Printing and Removing Duplicates in Arrays
by andye (Curate) on Aug 21, 2002 at 10:48 UTC
    Here's one way:
    my @ary1 = (1, 2, 3, 4, 5, 6, 7); my @ary2 = (6, 7, 8, 9, 10, 11); my %h1 = map {$_ => 1} @ary1; my %h2 = map {$_ => 1} @ary2; my %dupes; @ary1 = grep {(! (exists $h1{$_} and exists $h2{$_})) or do{$dupes{$_} +=1;0}} @ary1; @ary2 = grep {(! (exists $h1{$_} and exists $h2{$_})) or do{$dupes{$_} +=1;0}} @ary2; print "ary1 is @ary1 \n"; print "ary2 is @ary2 \n"; my @dupes = keys %dupes; print "dupes were @dupes \n";

    Hope that helps,
    andye.

    Edited to make dupes a hash rather than an array, to prevent dupes in the dupes!
    Another minor edit to prevent a warning


      That's nice. ++

      However, you don't need to check if an element exists in the current array:

      my @ary1 = (1, 2, 3, 4, 5, 6, 7); my @ary2 = (6, 7, 8, 9, 10, 11); my %h1; my %h2; @h1{@ary1} = undef; @h2{@ary2} = undef; my @dupes; @ary1 = grep {not exists $h2{$_} or not push @dupes, $_} @ary1; @ary2 = grep {not exists $h1{$_} } @ary2; print "ary1 is @ary1 \n"; print "ary2 is @ary2 \n"; print "dupes were @dupes \n";

      Or even just this:

      @dupes = grep { exists $h2{$_}} @ary1; @ary1 = grep {not exists $h2{$_}} @ary1; @ary2 = grep {not exists $h1{$_}} @ary2;

      --
      John.

        duh! (smacks own head) You're right.
        @ary1 = grep {!exists $h2{$_} or $dupes{$_}=0} @ary1; @ary2 = grep {!exists $h1{$_} } @ary2;

        andye.

        minor edit

Re: Printing and Removing Duplicates in Arrays
by tommyw (Hermit) on Aug 21, 2002 at 10:38 UTC

    Well, after the first match (0 vs 0), $array1size=10; $array2size=3; $count1=0; $count2=0; but @array1=(1,2,3,4,5,6,7,8,9) @array2=(1,4)

    You then increase $count1 to 1, and it's now pointing at the value 2, which is why you don't get a match on the value 1.

    When the 4s match, another element is deleted from both arrays, but $count1 still increases to try and look at all the original elements (and therefore falls of the end off the shortened array).

    --
    Tommy
    Too stupid to live.
    Too stubborn to die.

Re: Printing and Removing Duplicates in Arrays
by thor (Priest) on Aug 21, 2002 at 12:27 UTC
    Though your question has already been answered, I'll present another solution in the spirit of TMTOWTDI:
    use strict; my %hash; my @ary1 = qw(1 2 3 4 5); my @ary2 = qw(6 7 8 1 2); foreach (@ary1, @ary2){ $hash{$_}++; } foreach my $key (keys %hash){ print "$key showed up $hash{$key} times\n" if $hash{$key} != 1; }
    This has the advantage of not having to grep through some arrays, an operation that is potentially costly.

    thor

Re: Printing and Removing Duplicates in Arrays
by Basilides (Friar) on Aug 21, 2002 at 12:38 UTC
    Similar to thor's solution above--no greps--but this one'll also wipe out the dupes from your arrays:
    use strict; my @a = (0,1,2,3,4,5,6,7,8,9); my @b = (0,1,4); my @isect = (); my @diff = (); my %count = (); foreach my $e (@a) { $count{$e} = 1; } foreach my $e (@b) { $count{$e} += 2; } @a = @b = (); foreach my $e (keys %count) { if ($count{$e} == 1) {push @a, $e;} elsif ($count{$e} == 2) {push @b, $e;} else {print "$e ";} }
    For a bunch of good examples of this kind of stuff, try the Perl Cookbook, recipes 4.6 & 4.8.