tags:

views:

1557

answers:

4

How do I compare two hashes in Perl without using Data::Compare?

+4  A: 

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

Sinan Ünür
What is the difference between cmpStr and cmpStrHard in FreezeThaw?
biznez
+5  A: 

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.
FM
It looks like Test::Deep was inspired by is_deeply. My question is how do I make cmp_deeply part of a test instead of a test on its own? Because my list of tests only states 8, but everytime I use cmp_deeply, it counts as a test, making my actual number of tests 11 (because I call cmp_deeply 3 times) when I only have 8 functions. I do not want to increase the number of my tests. Is there a more viable solution?
biznez
@yskhoo. Every time you call one of the testing functions (`ok`, `cmp_deeply`, etc.) it counts as a test. As far as I know, there isn't a way to avoid that. If you don't want to commit in advance to a specific number of tests, you can do this when you load the testing module: `use Test::More qw(no_plan);`.
FM
You already asked this in http://stackoverflow.com/questions/1274756/how-can-i-use-perls-testdeepcmpdeeply-without-increasing-the-test-count. You did not answer why you cannot increase the number of tests, or what is so complicated about your data structure that you need to call cmp_deeply three times. Please step back from the questions you are asking and determine what the real problem is. If you would provide more information, maybe we can help.
Ether
+4  A: 

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.

Chas. Owens
+1  A: 

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;
zakovyrya