FAQ 4.44 How do I test whether two arrays or hashes are equal?

P

PerlFAQ Server

This is an excerpt from the latest version perlfaq4.pod, which
comes with the standard Perl distribution. These postings aim to
reduce the number of repeated questions as well as allow the community
to review and update the answers. The latest version of the complete
perlfaq is at http://faq.perl.org .

--------------------------------------------------------------------

4.44: How do I test whether two arrays or hashes are equal?

With Perl 5.10 and later, the smart match operator can give you the
answer with the least amount of work:

use 5.010;

if( @array1 ~~ @array2 )
{
say "The arrays are the same";
}

if( %hash1 ~~ %hash2 ) # doesn't check values!
{
say "The hash keys are the same";
}

The following code works for single-level arrays. It uses a stringwise
comparison, and does not distinguish defined versus undefined empty
strings. Modify if you have other needs.

$are_equal = compare_arrays(\@frogs, \@toads);

sub compare_arrays {
my ($first, $second) = @_;
no warnings; # silence spurious -w undef complaints
return 0 unless @$first == @$second;
for (my $i = 0; $i < @$first; $i++) {
return 0 if $first->[$i] ne $second->[$i];
}
return 1;
}

For multilevel structures, you may wish to use an approach more like
this one. It uses the CPAN module "FreezeThaw":

use FreezeThaw qw(cmpStr);
@a = @b = ( "this", "that", [ "more", "stuff" ] );

printf "a and b contain %s arrays\n",
cmpStr(\@a, \@b) == 0
? "the same"
: "different";

This approach also works for comparing hashes. Here we'll demonstrate
two different answers:

use FreezeThaw qw(cmpStr cmpStrHard);

%a = %b = ( "this" => "that", "extra" => [ "more", "stuff" ] );
$a{EXTRA} = \%b;
$b{EXTRA} = \%a;

printf "a and b contain %s hashes\n",
cmpStr(\%a, \%b) == 0 ? "the same" : "different";

printf "a and b contain %s hashes\n",
cmpStrHard(\%a, \%b) == 0 ? "the same" : "different";

The first reports that both those the hashes contain the same data,
while the second reports that they do not. Which you prefer is left as
an exercise to the reader.



--------------------------------------------------------------------

The perlfaq-workers, a group of volunteers, maintain the perlfaq. They
are not necessarily experts in every domain where Perl might show up,
so please include as much information as possible and relevant in any
corrections. The perlfaq-workers also don't have access to every
operating system or platform, so please include relevant details for
corrections to examples that do not work on particular platforms.
Working code is greatly appreciated.

If you'd like to help maintain the perlfaq, see the details in
perlfaq.pod.
 
J

John Bokma

John Small said:
But all the elements in the arrays being compared in this particular
program are all single "words". For this situation "@array1" eq
"@array2" does seem to work. Is there any reason to think "@array1" eq
"@array2" would not work under these conditions?

If these conditions always hold, it will always work. Note that the FAQ
answer has also specific conditions, and fails if those conditions don't
hold.
 
D

Dr.Ruud

if ("@array1" eq "@array2") ...

This seems to work for me.

Having parallel arrays is often a design flaw.

Replace for example by a hash, where the value is a counter.

perl -MData::Dumper -MList::MoreUtils=uniq -wle '
my @old = qw/ a b c d e f g h i j /;
my @new = qw/ 2 7 d e j k l /;
my %uniq;

++$_ for @uniq{ @old };
--$_ for @uniq{ @new };
delete @uniq{ grep !$uniq{ $_ }, keys %uniq };

print Dumper( \%uniq );

print uniq sort @old, @new;
'
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,962
Messages
2,570,134
Members
46,690
Latest member
MacGyver

Latest Threads

Top