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.

#!/usr/bin/perl # Tom Moertel <tom@moertel.com> 2004-10-12 use warnings; use strict; sub are_hashes_equal($$) { my ($a, $b) = @_; # 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; } # we use LectroTest to test whether the following # properties hold for our implementation above 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";

In reply to Re: Multiple loop variable in foreach statement by tmoertel
in thread Multiple loop variable in foreach statement by tc1364

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post, it's "PerlMonks-approved HTML":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.