in reply to How to check that keys in two hashes match and get the corresponding values

NewLondonPerl:

I'd suggest rethinking your data structure a bit. The reason you're having a hard time with it is that the data structure isn't regular, so your code is obfuscated by all sorts of special case handling. I couldn't tell what you're wanting to do by looking at your code.

Looking at the data, your code and the desired output gave me enough to go on, though. At first, I tried to clean up your code to get it going, but it was just too different from how I would've done it, that I kept getting confused. So I just started from scratch and came up with this:

$ cat 1028644.pl #!/usr/bin/perl use strict; use warnings; my $nfshashofhashes = { "bigstorderv_mpt" => { "%export_name" => "/bb/bigstor/derv", "%filer_device" => "nydevnfs_derv", "%filer_volume" => "/vol/derv", }, "bigstormtg_mpt" => { "%export_name" => "/bb/bigstor/mtgmodel", "%filer_device" => { "\@ridge" => "njdevnfs_mtge", "\@west" => "nydevnfs_mtge" }, "%filer_volume" => "/vol/mtge", }, "build10_mpt" => { "%export_name" => "/bb/source", "%filer_device" => { "\@ridge" => "rnap7751-s", "\@west" => "nydevnfs_sunbbsource" }, "%filer_volume" => { "\@ridge" => "/vol/sunbbsource_c", "\@west" => "/vol/sunbbsource" } }, "build11_mpt" => { "%export_name" => "/bb/source", "%filer_device" => { "fridge" => "rnap7751-s", "\@west" => "nydevnfs_sunbbsource", }, "%filer_volume" => { "\@ridge" => "/vol/sunbbsource_c", "\@west" => "/vol/sunbbsource", "qwest" => "/vol/sunquirks", } }, }; while ( my ($MPT, $rMPT) = each %{$nfshashofhashes} ) { die "MPT<$MPT> NOT A HASH!\n" unless ref $rMPT eq 'HASH'; die "MPT<$MPT> WRONG STRUCTURE!\n" unless exists $rMPT->{'%export_ +name'}; my $EXP = $rMPT->{'%export_name'}; # Set default value and hash ref for devices my ($rFILDEV, $DEVDFLT, $t); $t = $rMPT->{'%filer_device'}; if (ref $t eq 'HASH') { $rFILDEV = $t; $DEVDFLT = '????'; } else { $rFILDEV = { }; $DEVDFLT = $t; } # Same for volumes my ($rFILVOL, $VOLDFLT); $t = $rMPT->{'%filer_volume'}; if (ref $t eq 'HASH') { $rFILVOL = $t; $VOLDFLT = '????'; } else { $rFILVOL = { }; $VOLDFLT = $t; } # Match up the VOL and DEV entries in the hash. Missing values fo +r # DEV and VOL will be filled in with the DFLT values as needed. my %MATCHUP; $MATCHUP{$_}{VOL} = $rFILVOL->{$_} for keys %$rFILVOL; $MATCHUP{$_}{DEV} = $rFILDEV->{$_} for keys %$rFILDEV; # If both were scalars, MATCHUP is empty, so make a single matchin +g record $MATCHUP{'BAR'} = { DEV=>$DEVDFLT, VOL=>$VOLDFLT } if ! keys %MATC +HUP; # And our final results... for (keys %MATCHUP) { my $DEV = $MATCHUP{$_}{DEV} // $DEVDFLT; my $VOL = $MATCHUP{$_}{VOL} // $VOLDFLT; printf "%-20.20s %-20.20s %-20.20s %-20.20s\n", $MPT, $DEV, $VOL, $EXP; } } $ perl 1028644.pl bigstorderv_mpt nydevnfs_derv /vol/derv /bb/big +stor/derv build11_mpt ???? /vol/sunbbsource_c /bb/sou +rce build11_mpt rnap7751-s ???? /bb/sou +rce build11_mpt ???? /vol/sunquirks /bb/sou +rce build11_mpt nydevnfs_sunbbsource /vol/sunbbsource /bb/sou +rce build10_mpt rnap7751-s /vol/sunbbsource_c /bb/sou +rce build10_mpt nydevnfs_sunbbsource /vol/sunbbsource /bb/sou +rce bigstormtg_mpt njdevnfs_mtge /vol/mtge /bb/big +stor/mtgmodel bigstormtg_mpt nydevnfs_mtge /vol/mtge /bb/big +stor/mtgmodel

I think that'll do it for you. You didn't specify what you were expecting when you had two hashes with mismatched keys, so I added "build11_mpt" to demonstrate it. Feel free to change it as you need it.

Since I had trouble wrapping my head around your code, I fully expect you might have a little difficulty with mine, so feel free to ask questions.

...roboticus

When your only tool is a hammer, all problems look like your thumb.

  • Comment on Re: How to check that keys in two hashes match and get the corresponding values
  • Download Code

Replies are listed 'Best First'.
Re^2: How to check that keys in two hashes match and get the corresponding values
by NewLondonPerl1 (Acolyte) on Apr 15, 2013 at 03:35 UTC

    Thanks ever so much for your help Roboticus. I have tried this out and this is now matching up these key values perfectly. I just have one question though. Maybe it because I dont fully understand all of your code but when I run this its seems to print out lines more than once. This seems to happen when either %filer_device is a hash or %filer_volume is a hash or both are hashes. So for example in the following section:

    "rtsys_mpt": { "%export_name": "/bb/rtsys", "%filer_device": { "@west": "nydevnfs_rtsysgit", "@ridge": "njdevnfs_rtsysgit" }, "%filer_volume": "/vol/rtsysgit" }

    When I run your code on this and just purely print out the volume and device values i get the lines duplicated like so:

    njdevnfs_rtsysgit = /vol/rtsysgit nydevnfs_rtsysgit = /vol/rtsysgit njdevnfs_rtsysgit = /vol/rtsysgit nydevnfs_rtsysgit = /vol/rtsysgit

    All that I need is this:

    njdevnfs_rtsysgit = /vol/rtsysgit nydevnfs_rtsysgit = /vol/rtsysgit

    But for some reason its duplicated? I am not too sure why? and in this section where %filer_device and %filer_volume are both hashes it outputs the same lines 3 times:

    "build18_mpt": { "%export_name": "/bb/mobile", "%filer_device": { "@west": "nydevnfs_mob_build", "@ridge": "rnap2113-s" }, "%filer_volume": { "@west": "/vol/mob_build", "@ridge": "/vol/mob_build_c" } },
    nydevnfs_mob_build = /vol/mob_build rnap2113-s = /vol/mob_build_c nydevnfs_mob_build = /vol/mob_build rnap2113-s = /vol/mob_build_c nydevnfs_mob_build = /vol/mob_build rnap2113-s = /vol/mob_build_c

    All i need is the first two lines. The others are duplicates:

    nydevnfs_mob_build = /vol/mob_build rnap2113-s = /vol/mob_build_c

    Do you know why this is happening please?

      NewLondonPerl1:

      I'm not seeing the problem, so I guess you made some change that you haven't mentioned. Without making any changes other than adding your new test case:

      . . . snip . . . my $nfshashofhashes = { "rtsys_mpt" => { '%export_name' => '/bb/rtsys', '%filer_device' => { '@west' => 'nydevnfs_rtsysgit', '@ridge' => 'njdevnfs_rtsysgit', }, '%filer_volume' => '/vol/rtsysgit', }, "bigstorderv_mpt" => { . . . snip . . .

      I get the following, which seems to be what you're wanting:

      $ perl 1028644.pl bigstorderv_mpt nydevnfs_derv /vol/derv /bb/big +stor/derv build11_mpt ???? /vol/sunbbsource_c /bb/sou +rce build11_mpt rnap7751-s ???? /bb/sou +rce build11_mpt ???? /vol/sunquirks /bb/sou +rce build11_mpt nydevnfs_sunbbsource /vol/sunbbsource /bb/sou +rce build10_mpt rnap7751-s /vol/sunbbsource_c /bb/sou +rce build10_mpt nydevnfs_sunbbsource /vol/sunbbsource /bb/sou +rce rtsys_mpt njdevnfs_rtsysgit /vol/rtsysgit /bb/rts +ys rtsys_mpt nydevnfs_rtsysgit /vol/rtsysgit /bb/rts +ys bigstormtg_mpt njdevnfs_mtge /vol/mtge /bb/big +stor/mtgmodel bigstormtg_mpt nydevnfs_mtge /vol/mtge /bb/big +stor/mtgmodel

      ...roboticus

      When your only tool is a hammer, all problems look like your thumb.