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

Mobilized Monks,

Yes, it's "Yet Another Array Comparison Question". But for a particular case:

I have arrays of simple integers. All I want to do is test if @array_1 contains exactly the same set of integers as @array_2. Yes, or no.

So I figure I should be able to do:

@array_1 = sort(@array_1); @array_2 = sort(@array_2);
And if they contain the same set of integers, I now have two identical arrays, even if the sort is ascii-betical instead of true numerical.

THEN - and here's my question - if I can convert the array into a string with no separators, I've got two strings to compare for equality. BUT - other than something heavy like

$string = join("", @array_1);
is there some other way to make my string?

Thanks

P.S. - other brilliant ideas are more than welcome!




Forget that fear of gravity,
Get a little savagery in your life.

Replies are listed 'Best First'.
Re: Compare two arrays of simple numbers
by throop (Chaplain) on Oct 03, 2007 at 02:58 UTC
    Gentle Punch Card Don,

    Sorting is order N-LogN complexity. For very large arrays where you care about efficiency, there should be linear methods where you avoid the sort.

    If the numbers in the arrays were multi-digit and there were no repeats in either array, I'd suggest an approach like

    • Make each element of @array1 a key for a hash with any corresponding value.
    • Foreach element in array2, check to see if it exists.
    • If not, report failure.
    • If so, delete.
    • At the end, the hash should be empty.
    You've said in a later note that the numbers were single digit. Then either the arrays are short or there are duplicates. Maybe you don't care about complexity. But maybe you do; I'd modify the algorithm to something like
    my %vhash; foreach (@array1){ # Each $vhash{N} says how many time +s N showed up in array1 $vhash{$_}++}; foreach (@array2){ # Each appearance of N in array2 kno +cks down its count in vhash if(! exists $vhash{$_}){ print "Found too many $_ in array2"; exit} elsif($vhash{$_}==1){ delete $vhash{$_)} else{$vhash{$_}--}; if(keys %vhash){ print "Found too many ", join(' ', keys %vhash), "in array1\n"} else{ print "Yep, they matched!\n"}
    (not tested)

    throop

Re: Compare two arrays of simple numbers
by bruceb3 (Pilgrim) on Oct 03, 2007 at 00:00 UTC
    Perl will do the conversion for you-
    $string = "@array_l";
      Opps, that will add spaces into the string, which isn't what you wanted.
        Well, I suppose "1 3 5 7" is just as equal to "1 3 5 7" as "1357" is to "1357".

        Thanks.

        Update - in fact, I do believe it solves the issue our velveteen friend Cop mentions above, since "1 234" is clearly not equal to "12 34".

      A reply falls below the community's threshold of quality. You may see it by logging in.
Re: Compare two arrays of simple numbers
by GrandFather (Saint) on Oct 03, 2007 at 00:27 UTC

    you might not actually want to do it this way, but:

    use strict; use warnings; my @array_1 = (1, 12, 34, 50); my @array_2 = (1, 1234, 50); my @array_3 = (34, 12, 1, 50); for ([\@array_1, \@array_2], [\@array_1, \@array_3]) { if ("@{[sort @{$_->[0]}]}" eq "@{[sort @{$_->[1]}]}") { print "match: [@{$_->[0]}], [@{$_->[1]}]\n"; } else { print "mismatch: [@{$_->[0]}], [@{$_->[1]}]\n"; } }

    Prints:

    mismatch: [1 12 34 50], [1 1234 50] match: [1 12 34 50], [34 12 1 50]

    where the magic of interest is "@{[sort @array_1]}" eq "@{[sort @array_2]}".


    Perl is environmentally friendly - it saves trees
Re: Compare two arrays of simple numbers
by andreas1234567 (Vicar) on Oct 03, 2007 at 06:06 UTC
    You can use Test::Differences for array comparison:
    $ cat 642261.pl use strict; use warnings; use Test::More (tests => 2); use Test::Differences; my @foo = (1 .. 4); my @bar = (1 .. 4); eq_or_diff(\@foo, \@bar, q{compare foo with bar}); push @foo, 1; push @bar, 2; eq_or_diff(\@foo, \@bar, q{compare foo with bar}); __END__ $ perl 642261.pl 1..2 ok 1 - compare foo with bar not ok 2 - compare foo with bar # Failed test 'compare foo with bar' # at 642261.pl line 11. # +----+-----+----------+ # | Elt|Got |Expected | # +----+-----+----------+ # | 0|1 |1 | # | 1|2 |2 | # | 2|3 |3 | # | 3|4 |4 | # * 4|1 |2 * # +----+-----+----------+ # Looks like you failed 1 test of 2.
    --
    Andreas
Re: Compare two arrays of simple numbers
by Prof Vince (Friar) on Oct 03, 2007 at 08:24 UTC
    That can be solved in linear time with an auxiliary array.
    sub comp { my ($a, $b) = @_; return 0 if @$a != @$b; my @c; ++$c[$_] for @$a; --$c[$_] for @$b; $_ != 0 && return 0 for grep defined, @c; return 1; }
      return 0 if @$a != @$b;
      Well that's (worst case) O(n) right there. :-)

      Does != even have a meaning in list context ?

      Update: Ouch, I'm so wrong it's ridiculous.

      -David

        Well that's (worst case) O(n) right there. :-)
        That's what linear means.
        Does != even have a meaning in list context ?
        Edit: It doesn't force scalar context, but seems to compare array lengths. See :
        sub zero { return (0, 0) } print +(zero() == 2) ? "scalar\n" : "list\n"; my @a = (0, 1); my @b = (1, 0); my @c = (0, 2 , 1); print +(@a == @b) ? "same length\n" : "not\n"; print +(@a == @c) ? "same length\n" : "not\n";
        Anyway, I think perl doesn't actually build the lists and directly optimize that to the array size, which should make it constant time.
A reply falls below the community's threshold of quality. You may see it by logging in.