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

Hello Experts, I have started my perl journey 4 months ago, and I am enjoying and feeling good about it :) - I get a lot of help from PerlMonks!! Just got into the hashes and need some help figuring out how I compare the values inside a hash

foreach my $elem (@vgmap) { printf "$elem->{node}:$elem->{vg}:$elem->{maj_num}\n"; }
The output I get from the above is like this:
node1:vg1:36 node2:vg1:36 node1:vg2:37 node2:vg2:37 node1:vg3:38 node2:vg3:40
The third ":" delimited field is volume group major number, I'd like to compare that major number for each vg on the 2 nodes (node1 and node2) and make sure they match (for ex: vg1 has 36 on both nodes which is desirable but vg3 has a mismatch and I want to flag that). Thanks in advance!!

Replies are listed 'Best First'.
Re: Compare the values in the hash
by haukex (Archbishop) on Apr 28, 2019 at 13:02 UTC

    Here's one way to do it. I'm creating a hash of hashes, where the elements of the inner hash are array references (so a hash of arrays). This means that for vgs that all have the same maj_num, the hash should only have one key, whereas if the maj_nums are different, there's more than one key. The output generation uses join, map, and de-referencing operations (see perlreftut and perlref).

    use warnings; use strict; use Data::Dump; # debug my @vgmap = ( { node => "node1", vg => "vg1", maj_num => 36 }, { node => "node2", vg => "vg1", maj_num => 36 }, { node => "node1", vg => "vg2", maj_num => 37 }, { node => "node2", vg => "vg2", maj_num => 37 }, { node => "node1", vg => "vg3", maj_num => 38 }, { node => "node2", vg => "vg3", maj_num => 40 }, ); my %vgmap; for my $vgm (@vgmap) { push @{ $vgmap{ $vgm->{vg} }{ $vgm->{maj_num} } }, $vgm->{node}; } dd \%vgmap; # debug for my $vg (sort keys %vgmap) { my @maj_nums = sort keys %{ $vgmap{$vg} }; if ( @maj_nums != 1 ) { print "$vg: ", join( "; ", map { "$_ used on " . join ", ", @{ $vgmap{$vg}{$_}} } @maj_nums ), "\n"; } } __END__ { vg1 => { 36 => ["node1", "node2"] }, vg2 => { 37 => ["node1", "node2"] }, vg3 => { 38 => ["node1"], 40 => ["node2"] }, } vg3: 38 used on node1; 40 used on node2

      Exactly what I was looking for. Thank you so much

Re: Compare the values in the hash
by Marshall (Canon) on Apr 28, 2019 at 20:31 UTC
    Another idea for you... Sometimes Hash of Array is useful.
    #!/usr/bin/perl use strict; use warnings; my %hash; while (my $line = <DATA>) { next if $line =~ /^\s*$/; #skip blanks chomp $line; my ($value, $key) = split ':',$line,2; push @{$hash{$key}},$value; } foreach my $key (sort keys %hash) { print "$key => @{$hash{$key}} ERROR Single Node!\n" if @{$hash{$ke +y}}<2; } =prints vg3:38 => node1 ERROR Single Node! vg3:40 => node2 ERROR Single Node! =cut __DATA__ node1:vg1:36 node2:vg1:36 node1:vg2:37 node2:vg2:37 node1:vg3:38 node2:vg3:40
    Update: I did a very poor job of naming in the above example. Normally I would call a hash by the names of the values it contains...instead of just %hash, %nodes would be better. Of course some descriptive name for "vg1:36" is far better that just "$key". With the good names, foreach my $machine_port (sort keys %nodes) is much more readable. I have no idea whether "machine_port" is right or not because I have no idea what "vg1:36" means in the real world.

    HoA can be useful because multidimensional hashes require a loop for each dimension in order to traverse the entire HoHoH..