Yesterday I wanted to compare two hashes to see if they were the same. I looked around a little bit and found Data::Compare. It was good at telling me the two hashes were different, however, it did not tell me where. So, I wrote a small little subroutine to recursively check my hash of hashes (of hashes). It was able to identity where I had to look to make corrections, almost to the exact spot. (I am unsure how to compare arrays of hashes just yet which is why the following little subroutine will almost take you to the right spot.)

There are still holes in the script, but it worked for me today.

#!/usr/bin/perl use strict; use warnings FATAL => qw( all ); use Data::Compare; use Data::Dumper; # You can take out all instances of the subroutine 'line' to print wha +t you want in those places. sub deep_data_compare { my ($tab, $old_data, $new_data, $data) = @_; my $old = $old_data; my $new = $new_data; my $compare = new Data::Compare($old, $new); if ($compare->Cmp == 0) { line($tab,$data) if $data; if (ref($old) eq 'HASH' && ref($new) eq 'HASH') { line($tab+1,'old to new'); for (keys %$old) { deep_data_compare($tab+2,$_,$$old{$_},$$new{$_}); } } # I have not figured out this part yet. # elsif (ref($old) eq 'ARRAY' && ref($new) eq 'ARRAY') { # } else { print Dumper($new); print Dumper($old); } } } sub rline { my ($tab,$line) = @_; return qq(\t) x $tab.qq($line\n); } sub line { print rline(@_); } deep_data_compare(0, \%old_hash, \%new_hash, 'widgets');
No matter how hysterical I get, my problems are not time sensitive. So, relax, have a cookie, and a very nice day!
Lady Aleena
  • Comment on Using Data::Compare recursively to better identity differences between hashes
  • Download Code

Replies are listed 'Best First'.
Re: Using Data::Compare recursively to better identity differences between hashes
by Anonymous Monk on Oct 18, 2014 at 11:10 UTC

    There is also Data::Difference that compares hash & hash references, and shows where a difference exist.

    BTW, Data::Compare does have the facility to compare array references (see "ignore_hash_keys" option).

    Some time ago I wrote some code to dump the two data structures (via Data::Dumper) to two separate files (File::Temp) followed by file-difference (possibly Algorithm::Diff or Text::Diff; OTOH might have been a call to system diff(1)).

    For visual difference, see Text::ParagraphDiff (never used myself). Also, GNU diff (version: diff (GNU diffutils) 2.8.1) has the facility to show word differences, optionally in color.

      I am unsure how to compare arrays of hashes ... -- Lady_Aleena

      The comment "Data::Compare does have the facility to compare array references" does not apply with respect to the above doubt. With combination of ...

      # I have not figured out this part yet. # elsif (ref($old) eq 'ARRAY' && ref($new) eq 'ARRAY') { # }

      ... it seems you are unsure about comparison of array reference of hash references. (Loose language sinks ships. ;-) Regardless, you would need to loop over array (reference) elements near the beginning of the sub ...

      sub deep_data_compare { my ( $old, $new ) = @_; if (ref $old eq 'ARRAY' && ref $new eq 'ARRAY') { # Handle the case of uneven number of elements in # each array reference as you see fit. Here assumption # is that both references have the same number of # elements. for my $ix ( 0 .. $#{ $old } ) { deep_data_compare( map $_->[ $ix ], $old, $new ) } } ... }
        i just saw a tweet that said foreach \%hash ( @AoH ) { ... } is coming to perl5.22 (available in bleed now).
Re: Using Data::Compare recursively to better identity differences between hashes
by boftx (Deacon) on Oct 19, 2014 at 02:24 UTC

    You might take a look at the is_deeply test in Test::More and see if that (combined with $Data::Dumper::Sortkeys = 1;) might offer some insight to what you wish to accomplish.

    You must always remember that the primary goal is to drain the swamp even when you are hip-deep in alligators.