A quick way to test hashes for equality is to test that they
have identical sizes and, if so, that all of the key-value
pairs from the first hash have equal corresponding pairs in
the second. Other options are available in the perlfaq4
entry "How do I test whether two arrays or hashes are equal?"
But, let's run with the first option. Here is a straightforward
implementation:
sub are_hashes_equal($$) {
my ($a, $b) = @_; # hashrefs
# number of keys in hashes must be the same
return 0 unless keys %$a == keys %$b;
# and each key-value pair in %$a must have an
# identical key-value pair in %$b
while (my ($key_a, $val_a) = each %$a) {
return 0 unless exists $b->{$key_a}
&& $b->{$key_a} eq $val_a;
}
return 1;
}
(In your sample code, you printed out the key-value pairs that
tested as unequal. I'm not sure whether you did that for debugging
purposes or because your application really requires it. If the
latter, you make the above code behave that way by replacing the first
return 0 line with
($a,$b) = ($b,$a) if keys %$b > keys %$a
then removing the final return 1, and finally replacing the
remaining return 0 with the desired print
statement.)
Just to make sure our implementation really works, let's test it with
Test::LectroTest.
We assert that the following four properties hold:
use Test::LectroTest;
Property {
##[ h <- Hash( Int, Int ) ]##
are_hashes_equal( $h, $h ) == 1;
}, name => "equal hashes are recognized as equal";
Property {
##[ h <- Hash( Int, Int, length=>[1,] ) ]##
my %h_diff = %$h;
delete $h_diff{scalar each %$h}; # delete 1st key
are_hashes_equal( $h, \%h_diff ) == 0;
}, name => "differences in quantity of keys are detected";
Property {
##[ h <- Hash( Int, Int, length=>[1,] ) ]##
my %h_diff = %$h;
delete $h_diff{scalar each %$h}; # delete 1st key
$h_diff{a} = 1; # replace with "a" key
are_hashes_equal( $h, \%h_diff ) == 0;
}, name => "differences in values of keys are detected";
Property {
##[ h <- Hash( Int, Int, length=>[1,] ) ]##
my %h_diff = %$h;
$h_diff{scalar each %$h}++; # increment 1st value
are_hashes_equal( $h, \%h_diff ) == 0;
}, name => "differences in values are detected";
And do the properties hold for our implementation?
1..4
ok 1 - 'equal hashes are recognized as equal' (1000 attempts)
ok 2 - 'differences in quantity of keys are detected' (1000 attempts)
ok 3 - 'differences in values of keys are detected' (1000 attempts)
ok 4 - 'differences in values are detected' (1000 attempts)
Cheers!
Tom
(Update: Added comment to make clear that the function takes two hashrefs.)
P.S. Below is all of the code from this post, in ready to run format.
|