How do I compare two hashes in Perl without using Data::Compare?
The best approach differs according to your purposes. The FAQ item mentioned by Sinan is a good resource: How do I test whether two arrays or hashes are equal?. During development and debugging (and of course when writing unit tests) I have found Test::More
to be useful when comparing arrays, hashes, and complex data structures. A simple example:
use strict;
use warnings;
my %some_data = (
a => [1, 2, 'x'],
b => { foo => 'bar', biz => 'buz' },
j => '867-5309',
);
my %other_data = (
a => [1, 2, 'x'],
b => { foo => 'bar', biz => 'buz' },
j => '867-5309x',
);
use Test::More tests => 1;
is_deeply(\%other_data, \%some_data, 'data structures should be the same');
Output:
1..1
not ok 1 - data structures should be the same
# Failed test 'data structures should be the same'
# at _x.pl line 19.
# Structures begin differing at:
# $got->{j} = '867-5309x'
# $expected->{j} = '867-5309'
# Looks like you failed 1 test of 1.
Compare is not a detailed enough phrase when talking about hashes. There are many ways to compare hashes:
Do they have the same number of keys?
if (%a == %b) {
print "they have the same number of keys\n";
} else {
print "they don't have the same number of keys\n";
}
Are the keys the same in both hashes?
if (%a != %b) {
print "they don't have the same number of keys\n";
} else {
my %cmp = map { $_ => 1 } keys %a;
for my $key (keys %b) {
last unless exists $cmp{$key};
delete $cmp{$key};
}
if (%cmp) {
print "they don't have the same keys\n";
} else {
print "they have the same keys\n";
}
}
Do they have the same keys and the same values in both hashes?
if (%a != %b) {
print "they don't have the same number of keys\n";
} else {
my %cmp = map { $_ => 1 } keys %a;
for my $key (keys %b) {
last unless exists $cmp{$key};
last unless $a{$key} eq $b{$key};
delete $cmp{$key};
}
if (%cmp) {
print "they don't have the same keys or values\n";
} else {
print "they have the same keys or values\n";
}
}
Are they isomorphic (I will leave this one up to the reader as I don't particularly want to try implementing it from scratch)?
Or some other measure of equal?
And, of course, this code only deals with simple hashes. Adding complex data structures makes it even more complex.
Quick, dirty, and I'm sure not that efficient:
use strict;
use warnings;
use Data::Dumper;
sub compare ($$) {
local $Data::Dumper::Terse = 1;
local $Data::Dumper::Indent = 0;
Dumper(shift) eq Dumper(shift);
}
my %a = ( foo => 'bar', bar => [ 0 .. 3 ] );
my %b = ( foo => 'bar', bar => [ 0 .. 3 ] );
my %c = ( foo => 'bar', bar => [ 0 .. 4 ] );
print Dumper compare \%a, \%b;
print Dumper compare \%a, \%c;