Beefy Boxes and Bandwidth Generously Provided by pair Networks
Don't ask to ask, just ask

Comparing contents of 2 Hashes of Hashes

by Tuna (Friar)
on Aug 16, 2001 at 15:34 UTC ( [id://105333]=perlquestion: print w/replies, xml ) Need Help??

Tuna has asked for the wisdom of the Perl Monks concerning the following question:

I need to compare the contents of two HoH. Each hash represents files from a local cluster of machines and files in a remote cluster of machines. The code below correctly populates them both, but I don't know how to access each element for comparison.

What I mean by comparison is each hash must contain the same keys and key values.

#!/usr/bin/perl -w use strict; use Digest::MD5; use Data::Dumper; my(%localDigest, %remoteDigest ); my ($file, $md5, $digest, $key, $clusterHost); my @files = (@ARGV); my @hosts = ("Maleah", "Austin"); foreach $clusterHost(@hosts) { foreach $file(@files) { open(FILE, $file) or die "Can't open '$file': $!"; binmode(FILE); $md5 = Digest::MD5->new; while (<FILE>) { $md5->add($_); $digest = $md5->hexdigest; $localDigest{$clusterHost}{$file} = $digest; $remoteDigest{$clusterHost}{$file} = $digest; } close(FILE); } } print Dumper (%localDigest,%remoteDigest );

Specifically, what I need to compare is, ie:

%localDigest $VAR1 = 'Austin'; $VAR2 = { './' => 'ad65a01b783248a21fcea95979a265a0', '/etc/passwd' => 'c978c29a59ba0138e5ed0ca325f7ec1e' }; $VAR3 = 'Maleah'; $VAR4 = { './' => 'ad65a01b783248a21fcea95979a265a0', '/etc/passwd' => 'c978c29a59ba0138e5ed0ca325f7ec1e' };
%remoteDigest $VAR5 = 'Austin'; $VAR6 = { './' => 'ad65a01b783248a21fcea95979a265a0', '/etc/passwd' => 'c978c29a59ba0138e5ed0ca325f7ec1e' }; $VAR7 = 'Maleah'; $VAR8 = { './' => 'ad65a01b783248a21fcea95979a265a0', '/etc/passwd' => 'c978c29a59ba0138e5ed0ca325f7ec1e' };

Thanks, once again,

Replies are listed 'Best First'.
Re: Comparing contents of 2 Hashes of Hashes
by trantor (Chaplain) on Aug 16, 2001 at 15:47 UTC
Re: Comparing contents of 2 Hashes of Hashes
by MZSanford (Curate) on Aug 16, 2001 at 15:44 UTC
    My first thought (untested, but should work) :
    sub compare_hohs { my ($localhref,$remhref) = @_; foreach my $mach (keys %{ $localhref }) { foreach my $file (keys %{ $localhref->{$mach} }) { # have machine and file if ($localhref->{$mach}{$file} != $remhref->{$mach}{$file} +) { print "$mach:$file mismatched\n"; ## do something with mis matched ## trnasfer i presume } } } }

    Thus spake the Master Programmer:
    "When you have learned to snatch the error code from the trap frame, it will be time for you to leave."
    -- The Tao of Programming
Re: Comparing contents of 2 Hashes of Hashes
by Trimbach (Curate) on Aug 16, 2001 at 15:47 UTC
    I'm assuming that the code you posted is a little stripped down from the real thing, because as written %localdigest and %remotedigest are guaranteed to be identical (you assign $digest to each hash one after the other without modifying $digest in between.)

    Anyway, assuming the hashes are actually different, this ought to work:

    foreach $clusterhost(@hosts) { foreach $file(@files) { if ($localdigest{$clusterhost}{$file} ne $remotedigest{$cluster +host}{$file}) { $error=1; print "The local $file on $clusterhost does not equal t +he remote $file.\n"; } } } if (!$error) { print "All files matched on all hosts.\n"; }

    Gary Blackburn
    Trained Killer

      Yes, way trimmed down! First, the code will populate HoH1 with locally generated config files. Once they are distributed to their respective hosts, we will calculate checksums after the transfer, populate HoH2, and compare.
Re: Comparing contents of 2 Hashes of Hashes
by Monky Python (Scribe) on Aug 16, 2001 at 16:04 UTC
    following should work:

    foreach $host (keys %localDigest) { foreach $file (keys %{ $localDigest{$host} }) { if (exists $remoteDigest{$host}{$file}) { # replace with compare print "$localDigest{$host}{$file} = $remoteDigest{$host}{$file} +\n"; } else { print "file $host $file missing\n"; } } }

    isn't it possible to compare your files,host and checksum in your original foreach loop, instead of building this complex hash structure?


Re: Comparing contents of 2 Hashes of Hashes
by premchai21 (Curate) on Aug 16, 2001 at 22:42 UTC
    Use any serializer; the most common is Data::Dumper, but there's also XML::Dumper, Data::Denter, plus a few others. You can just eq the serialized versions, or if they're big, eq the MD5ed serialized versions.
Re: Comparing contents of 2 Hashes of Hashes
by thraxil (Prior) on Aug 16, 2001 at 20:07 UTC

    i've got a slightly more generic solution here. it will compare two arbitrarily deeply nested and complex data structures.

    anders pearson

Re: Comparing contents of 2 Hashes of Hashes
by nakor (Novice) on Aug 16, 2001 at 18:18 UTC
    # call as cmp_hash(\%localDigest, \%remoteDigest) # returns true or false (%localDigest == %remoteDigest) sub cmp_hash ($$) { my($h1, $h2) = @_; my @a1 = sort %$h1; my @a2 = sort %$h2; return 0 unless scalar(@a1) == scalar(@a2); for (my $i = 0; $i < $#a1; $i++) { # can't use foreach(@a1) here because we need to # know our position to find the corresponding # element in @a2 if (ref($a1[$i]) eq 'HASH') { return 0 unless ref($a2[$i]) eq 'HASH'; return 0 unless cmp_hash($a1[$i], $a2[$i]); next; } return 0 unless $a1[$i] eq $a2[$i]; } return 1; }

Log In?

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://105333]
Approved by root
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others musing on the Monastery: (5)
As of 2024-05-19 06:12 GMT
Find Nodes?
    Voting Booth?

    No recent polls found