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

so, i got this from the perl documentation; it's perfect for what i need, except for the fact that it does not preserve the original orders of @array1 and/or @array2. how would i go about tweaking this so that it will preserve the order (by key or value)? i kinda understand what's going on, but i don't fully understand what is going on here...
@union = @intersection = @difference = (); %count = (); foreach $element (@array1, @array2) { $count{$element}++ } foreach $element (keys %count) { push @union, $element; push @{ $count{$element} > 1 ? \@intersection : \@difference + }, $element; }

Replies are listed 'Best First'.
Re: tweaking of perldoc function (sorting/preserving order)
by ikegami (Patriarch) on Jan 18, 2008 at 01:43 UTC
    my @array1 = (1,2,3,4,5); my @array2 = (4,5,6,7,8); my %counts; my @union = grep ++$counts{$_} == 1, @array1, @array2; my @intersection = grep $counts{$_} == 2, @array1; my @difference = grep $counts{$_} == 1, @array1; my @intersection_c = grep $counts{$_} == 1, @array1, @array2; print "Union: @union\n"; print "Intersection: @intersection\n"; print "Difference: @difference\n"; print "Complement of intersection: @intersection_c\n";
    Union: 1 2 3 4 5 6 7 8 Intersection: 4 5 Difference: 1 2 3 Complement of intersection: 1 2 3 6 7 8

    Note that your code (and almut's) incorrectly calculates the difference.

      ikegami:

      Note that your code (and almut's) incorrectly calculates the difference.

      perlfaq4 (from where the code is taken):

      Note that this is the symmetric difference, that is, all elements in either A or in B but not in both. Think of it as an xor operation.

      That means that what ikegami calls "complement of intersection" is was perlfaq4 calls "(symmetric) difference". Different authors have different definitions for difference and the symbol they use, such as - or \.

      perlfaq4 is correct with the definition of difference it provides.

      lodin

Re: tweaking of perldoc function (sorting/preserving order)
by almut (Canon) on Jan 18, 2008 at 01:42 UTC

    You could do:

    my @array1 = (1,2,3,4,5); my @array2 = (4,5,6,7,8); @union = @intersection = @difference = (); %count = (); foreach $element (@array1, @array2) { $count{$element}++ } foreach $element (@array1, @array2) { if (exists $count{$element}) { push @union, $element; push @{ $count{$element} > 1 ? \@intersection : \@difference } +, $element; delete $count{$element}; } } print "Union: @union\n"; print "Intersection: @intersection\n"; print "Difference: @difference\n";

    Output:

    Union: 1 2 3 4 5 6 7 8 Intersection: 4 5 Difference: 1 2 3 6 7 8

    Update: as to the incorrect difference (as pointed out by ikegami): the OP said "it's perfect for what i need, except for ... the order", so I didn't consider it my business to redefine his/her notion of "difference", but rather just modify the code to keep the original ordering...

Re: tweaking of perldoc function (sorting/preserving order)
by poolpi (Hermit) on Jan 18, 2008 at 09:10 UTC
    #!/usr/bin/perl use strict; use warnings; use List::Compare; use Data::Dumper; my @array1 = (1,2,3,4,5); my @array2 = (4,5,6,7,8); #my $lc = List::Compare->new( '-u', \@array1, \@array2); my $lc = List::Compare->new( \@array1, \@array2); my $compare = { 'Union' => [ $lc->get_union ], 'Intersection' => [ $lc->get_intersection ], 'Difference' => [ $lc->get_unique ], 'Sym_diff' => [ $lc->get_symmetric_difference ] }; $Data::Dumper::Indent = 1; print Dumper($compare);

    Output:
    $VAR1 = { 'Intersection' => [ '4', '5' ], 'Sym_diff' => [ '1', '2', '3', '6', '7', '8' ], 'Difference' => [ '1', '2', '3' ], 'Union' => [ '1', '2', '3', '4', '5', '6', '7', '8' ] };

    HTH,

    PooLpi

      List::Compare doesn't necessarily preserve any order. The default behaviour is simply to sort the lists by Perl's default sort order. Without sorting no promise about ordering is given. Keeping original order is what the OP asks for (dispite the title), so List::Compare is unfortunately not a reliable solution.

      lodin

Re: tweaking of perldoc function (sorting/preserving order)
by lodin (Hermit) on Jan 18, 2008 at 08:44 UTC

    How do you define order for intersection? Take this for instance:

    my @a = (1,2,3); my @b = reverse @a;
    The intersection will now be all element in @a (or @b), but in which order?

    lodin