0

I have a hash of hashes, that is, hash and hash references in my data structure. Can I iterate through the deepest hash when I only have the main hash name and no key of the deepest hash?

my %gates_info=(
    'order' => {
        'nand' => {
            'nand2_1' =>2,
            'nand2_5' =>-1,
            'nand2_4' =>2,
            'nand2_6' =>-1,
            'nand2_2' =>2,
            'nand2_3' =>3
        },
        'and' => {
            'and2'=>1,
            'and3'=>2,
        },
    }
);

sub max_gate_order {
    print values (%{$gates_info{'order'}});
    my @arr = (sort {$a <=> $b} values %{$gates_info{'order'}});
    return $arr[-1];
}

I want to iterate over the whole hash when I have just its name %gates_info and no keys such as "nand" or "and". What I am trying to achieve is to get the highest numeric value in each of the gates by sorting. Such as 3 in nand case and 2 in and case. Sub max_gate_order is used for sorting and returning highest value. Thanks

Håkon Hægland
  • 32,521
  • 18
  • 64
  • 139

3 Answers3

2

keys will give you those keys.

sub max_gate_order {
   my ($gates_info) = @_;
   my $max_order;
   my @gates;
   for my $gate_type (keys %{ $gates_info->{order} }) {
      for my $gate_id (keys %{ $gates_info->{order}{$gate_type} }) {
         my $order = $gates_info->{order}{$gate_type}{$gate_id};
         $max_order //= $order;
         if ($order >= $max_order) {
            if ($order > $max_order) {
               $max_order = $order;
               @gates = ();
            }

            push @gates, $gate_id;
         }
      }
   }

   return @gates;
}

my @gates = max_gate_order(\%gates_info);

The above returns all the gates with the highest order.

If you want both the gate type and the gate id, replace

push @gates, $gate_id;

with

push @gates, [ $gate_type, $gate_id ];

or

push @gates, [ $gate_type, $gate_id, $order ];
ikegami
  • 322,729
  • 15
  • 228
  • 466
2

This is a longer, more redundant solution, more of an exercise really. But you might find it interesting to examine the structure of the hash iteration this way. (I know I do!) This could be useful if you only have the main hash name (%gates_info), and none of the keys under that. Which is what your question implies is the case. This pulls out all the key and value names as deep as the hash goes, in case any of those might be useful. I also uploaded a working example. (Note this does require knowing how many levels deep your hash is.)

#!/usr/bin/perl
use strict;
use warnings;
use Data::Dumper;


my %gates_info=(
    'order' => {
        'nand' => {
            'nand2_1' =>2,
            'nand2_5' =>-1,
            'nand2_4' =>2,
            'nand2_6' =>-1,
            'nand2_2' =>2,
            'nand2_3' =>3
        },
        'and' => {
            'and2'=>1,
            'and3'=>2,
        },
    }
);
print Dumper %gates_info;
print "\n\n";

my @gate;
my $hival; 

foreach my $gate (sort keys %gates_info) {
 foreach my $gatekey (sort keys %{$gates_info{$gate}}) {
   foreach my $deepkey (sort keys %{$gates_info{$gate}{$gatekey}}) {
   my $deepvalue = $gates_info{$gate}->{$gatekey}->{$deepkey};
push @gate, $deepvalue;
@gate = sort @gate;
$hival = $gate[@gate - 1];
print "Gate is $gate, gatekey is $gatekey, deepkey is $deepkey, deepvalue is $deepvalue\n"; 
  } 
print "\nGatekey is $gatekey, highest value is $hival\n\n";
@gate = (); #empty gate array
 } 
}

exit 0;

The output of the code is:

$VAR1 = 'order';
$VAR2 = {
          'and' => {
                     'and2' => 1,
                     'and3' => 2
                   },
          'nand' => {
                      'nand2_3' => 3,
                      'nand2_6' => -1,
                      'nand2_4' => 2,
                      'nand2_5' => -1,
                      'nand2_2' => 2,
                      'nand2_1' => 2
                    }
        };


Gate is order, gatekey is and, deepkey is and2, deepvalue is 1
Gate is order, gatekey is and, deepkey is and3, deepvalue is 2

Gatekey is and, highest value is 2

Gate is order, gatekey is nand, deepkey is nand2_1, deepvalue is 2
Gate is order, gatekey is nand, deepkey is nand2_2, deepvalue is 2
Gate is order, gatekey is nand, deepkey is nand2_3, deepvalue is 3
Gate is order, gatekey is nand, deepkey is nand2_4, deepvalue is 2
Gate is order, gatekey is nand, deepkey is nand2_5, deepvalue is -1
Gate is order, gatekey is nand, deepkey is nand2_6, deepvalue is -1

Gatekey is nand, highest value is 3
Bman70
  • 616
  • 5
  • 10
0
sub max_gate_order {

    my %hash =();
    foreach my $k (keys %{$gates_info{'order'}}) {
        my @arr = (sort {$a <=> $b} values %{$gates_info{'order'}->{$k}});
        $hash{$k} = $arr[-1];       
    }   
    return \%hash;

}
Steffen Ullrich
  • 90,680
  • 7
  • 99
  • 140
  • 1
    It is unclear what you are trying to achieve with this in the first place since the return value is different from what you want in your question and you don't describe what it should do. Also, it can not handle arbitrary deep nested hashes which looked like a requirement for me from your question but maybe its not. – Steffen Ullrich Apr 18 '19 at 11:27
  • 1
    @Steffen Ullrich, Re "*Also, it can not handle arbitrary deep nested hashes*", There's no indication this is necessary. Quite the opposite, this seems unwanted. – ikegami Apr 18 '19 at 11:43
  • 2
    Hi, please add some explanation to why this is a solution. Thanks – d_kennetz Apr 18 '19 at 17:01
  • @d_kennetz; First we use keys function to get all keys of the above hash pointed by order. Then we used the specific key to get the hash value which is/are other hashes and then on the same line used the values function to get the values of the deepest hash. The values are numeric so we applied sort function which sorts hashes by values. In order to sort in ascending order we used $a=>$b, special variables. Had we required descending we would have used $b=>$a. So we got the highest value of every key in deepest hash so we assigned it to a hash and returned its reference. – programmingzeal Apr 21 '19 at 13:36