Beefy Boxes and Bandwidth Generously Provided by pair Networks
laziness, impatience, and hubris
 
PerlMonks  

what's the best way to compare two 2D hashes?

by coontie (Sexton)
on Jun 22, 2005 at 18:59 UTC ( [id://469130]=perlquestion: print w/replies, xml ) Need Help??

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

Hi, all. I've got two hashes created from external sources: $foo{$i}{$j} and $bar{$i}{$i} I need to know if there are any matches between foo & bar, for all $i & $j. Currently, I've 4 nested foreach loops:
foreach i in foo foreach j in foo foreach i in bar foreach j in bar COMPARE
is there a better way of doing this? (the code above works but ugly)

Thank you.

Replies are listed 'Best First'.
Re: what's the best way to compare two 2D hashes?
by tlm (Prior) on Jun 22, 2005 at 19:09 UTC

    Here's a straightforward approach:

    for my $k1 ( keys %foo ) { next if not defined $bar{ $k1 }; for my $k2 ( keys %{ $foo{ $k1 } } ) { next if not defined $bar{ $k1 }{ $k2 }; dance() if $foo{ $k1 }{ $k2 } eq $bar{ $k1 }{ $k2 }; } }
    If the number of keys in one hash is much greater than the number of keys in the other, it may pay to optimize this search so that the iteration happens over the keys of the hash with fewer keys.

    I show a slightly "fancier" approach below, because I think you may find it instructive, but IMO the first approach is far preferable for production code:

    for my $k1 ( grep defined $h2{ $_ }, keys %h1 ) { for my $k2 ( grep defined $h2{ $k1 }{ $_ }, keys %{ $h1{ $k1 } } ) { dance() if $h1{ $k1 }{ $k2 } eq $h2{ $k1 }{ $k2 }; } }

    the lowliest monk

Re: what's the best way to compare two 2D hashes?
by dragonchild (Archbishop) on Jun 22, 2005 at 19:12 UTC
    Test::More is_deeply() - if you can't use it directly, you can grab what Schwern did and go from there.

    My criteria for good software:
    1. Does it work?
    2. Can someone else come in, make a change, and be reasonably certain no bugs were introduced?
Re: what's the best way to compare two 2D hashes?
by moot (Chaplain) on Jun 22, 2005 at 20:57 UTC
    Since no-one has mentioned it, you might also want to look into Struct::Compare.

    Now hiring in Atlanta. /msg moot for details.
Re: what's the best way to compare two 2D hashes?
by ambrus (Abbot) on Jun 22, 2005 at 20:03 UTC

    Create a hash of values. Here's some untested code:

    my $values; for $i (keys(%foo)) { for $j (keys(my $fi = $foo{$i})) { $values{$fi{$j}} ||= [$i, $j]; } } COMPARE: for $i (keys(%bar)) { for $j (keys(my $bi = $bar{$i})) { my $c = $values{$bi{$j}} and do { print "match found: \$foo{" . $$c[0] . "}{" . $$c[1] . "} +eq \$bar{" . $i . "}{" . $j . "}\n"; # what makes you think I don't l +ike interpolation? last COMPARE; }; } }
Re: what's the best way to compare two 2D hashes?
by borisz (Canon) on Jun 23, 2005 at 08:30 UTC
      Let me try this data::compare -- it seems to be the cleanest way so far.
Re: what's the best way to compare two 2D hashes?
by TedPride (Priest) on Jun 22, 2005 at 21:55 UTC
    NOTE: The following assumes both keys and value have to match. If you just want to check for value matches, there are a couple different ways you could go about it, depending on whether all values in each hash are unique or not, and if not, whether you want all matches listed or just the first.
    use strict; use warnings; my ($k1, $k2, %foo, %bar); %foo = ( 'a' => { 'x' => 1, 'y' => 3 }, 'b' => { 'x' => 4, 'y' => 4 } ); %bar = ( 'a' => { 'x' => 1, 'y' => 2 }, 'b' => { 'x' => 3, 'y' => 4 } ); for $k1 (sort keys %foo) { for $k2 (sort keys %{$foo{$k1}}) { print "\$foo{$k1}{$k2} eq \$bar{$k1}{$k2} with value $foo{$k1} +{$k2}\n" if $foo{$k1}{$k2} eq $bar{$k1}{$k2}; } }
    EDIT: Here's some code to report all value matches:
    use strict; use warnings; use Data::Dumper; my ($k1, $k2, %foo, %bar, %fval, %bval); %foo = ( 'a' => { 'x' => 1, 'y' => 3 }, 'b' => { 'x' => 4, 'y' => 4 } ); %bar = ( 'a' => { 'x' => 1, 'y' => 2 }, 'b' => { 'x' => 3, 'y' => 4 } ); for $k1 (keys %foo) { for $k2 (keys %{$foo{$k1}}) { push @{$fval{$foo{$k1}{$k2}}}, "$k1\t$k2"; } } for $k1 (keys %bar) { for $k2 (keys %{$bar{$k1}}) { push @{$bval{$bar{$k1}{$k2}}}, "$k1\t$k2"; } } for $k1 (sort keys %fval) { if (exists $bval{$k1}) { print "Value $k1 matches for:\n"; for (sort @{$fval{$k1}}) { @_ = split /\t/; print " \$foo{$_[0]}{$_[1]}\n"; } for (sort @{$bval{$k1}}) { @_ = split /\t/; print " \$bar{$_[0]}{$_[1]}\n"; } print "\n"; } }

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others wandering the Monastery: (4)
As of 2024-04-26 08:23 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found