How to deal with hashes of hashes - Part 1

The following example shows you how to generate a Perl hash of hashes using a while loop.

#!/usr/local/bin/perl
 
use warnings;
use strict;
 
my %HoH;
while(<DATA>) {
  chomp;
  s/^(.*?):\s*//;
  $HoH{$1} = {split};
}
 
# print the @HoH hash       
 
foreach my $itemKey ( keys %HoH ) {
  print "$itemKey: ";
  foreach my $key ( keys %{ $HoH{$itemKey} } ) {
    print "$key = $HoH{$itemKey}{$key} ";
  }
  print "\n";
}
 
__DATA__
item1: price 19 quantity 12
item2: price 32 quantity 92
item3: price 77 quantity 11

In order to read the elements of the %HoH hash, I used the __DATA__ pseudo file handle. The while loop will read from <DATA> handle all the lines up to EOF.

Inside the while loop:

  • each line is assigned in turn to $_
  • the chomp function will remove the trailing newline from $_
  • the substitution operator s/// searches $_ and store in $1 the string that matches the components enclosed by the group of parentheses and removes from $_ this string, the colon and any whitespace that follows the colon
  • the split function will split the content stored in $_ into an anonymous array using the whitespace delimiter; {} is the hash constructor and it will return a reference to an anonymous hash (every two elements from the anonymous array are grouped as a hash (key, value) pair element)
  • a new ($key, $val) pair element will be added to the hash table (in the $key will be stored the string assigned to $1 and in the $val will be stored the hash reference)

Finally, two nested foreach loops are used to print the Perl %HoH hash. The output produced by this code is as follows:

    item3: quantity = 11 price = 77
    item1: quantity = 12 price = 19
    item2: quantity = 92 price = 32

The following example shows you how to loop over a Perl hash of hashes using for statement and how to print its elements. Don’t mix for with foreach, even if sometimes you spell foreach as for.

Look at the following sample:

#!/usr/bin/perl
 
use strict;
use warnings;
 
# initialize a hash of hashes
my %HoH = (
 item1 => {price => 19, quantity => 12},
 item2 => {price => 32, quantity => 92},
 item3 => {price => 77, quantity => 10}
);           
 
my @tmpo = keys %HoH;
for(my $i=0; $i<=$#tmpo; $i++) {
  print "$tmpo[$i]: ";
  my @tmpi = keys %{$HoH{$tmpo[$i]}};
  for(my $j=0; $j<=$#tmpi; $j++) {
    print "$tmpi[$j] = $HoH{$tmpo[$i]}{$tmpi[$j]} ";
  }
  print "\n"; 
}
First we populate a hash of hashes with a few entries.

We have three pair elements having respectively as keys: item1, item2 and item3.

Each key has associated as value a reference to an anonymous hash, the {} is the hash constructor and returns a reference to an anonymous hash.

To traverse and print the elements of the hash of hashes, we used two nested for.

The outer for is looping through the keys of the outer hash (i.e. %HoH) while the inner for is looping through the keys of the inner hashes.

Next the keys of the Perl %HoH hash of hashes are saved in the @tmpo array variable.

The outer for iterates over the indices of the @tmpo array by using the $i scalar variable. The expression $#tmpo means the last index of the @tmpo array.

Inside the outer for block, first we print the current key stored in the @tmpo array.

Here $tmpo[$i] means the element of @tmpo array which has the index $i. Next, the keys of the inner hash are saved in the @tmpi array variable.

The inner for iterates over the indices of the @tmpi array by using the $j scalar variable.

To access the value of an element from the inner hash, we use the $HoH{$keyo}{$keyi} notation where $keyo, $keyi are keys in the outer and inner hash respectively.

After running this code, you’ll get as output:

    item3: quantity = 10 price = 77
    item1: quantity = 12 price = 19
    item2: quantity = 92 price = 32

The following example shows you how to use foreach to loop over a Perl hash of hashes and print its elements.

Here it’s a simple code snippet:

#!/usr/bin/perl
 
use strict;
use warnings;
 
# initialize a hash of hashes
 
my %HoH = (
 item1 => {price => 19, quantity => 12},
 item2 => {price => 32, quantity => 92},
 item3 => {price => 77, quantity => 10}
);           
 
foreach my $oKey ( keys %HoH ) {
  print "$oKey: ";
  foreach my $iKey ( keys %{ $HoH{$oKey} } ) {
    print "$iKey = $HoH{$oKey}{$iKey} ";
  }
  print "\n";
}
The output:
 
    item3: quantity = 10 price = 77
    item1: quantity = 12 price = 19
    item2: quantity = 92 price = 32

We use the same %HoH hash of hashes as in the previous example.

To print the elements of the %HoH aggregate, we used two nested foreach loops.

In the outer foreach loop, we iterate over the keys of the outer hash, and in the inner foreach loop we iterate over the keys of the inner hashes. The keys function returns a list with the keys of the outer/inner hash. $oKey is the current key of the outer hash and $HOA{$oKey} is its associated value that is a reference to the corresponding inner  hash.

To dereference the inner hash references, we need to precede them with the % symbol.

The grep function can be used to loop over a Perl hash of hashes and filter some data.

The following example shows you how grep the keys of a %HoH hash of hashes and get only those keys from the main hash where the corresponding inner hashes match a specific condition.

See the code:

#!/usr/bin/perl
 
use strict;
use warnings;
 
# initialize a hash of hashes
my %HoH = (
 item1 => {price => 19, quantity => 12},
 item2 => {quantity => 92},
 item3 => {price => 77, quantity => 10}
);           
 
my @keys = grep { defined $HoH{$_}{price} } keys %HoH;
print "@keys\n";
# it prints: item3 item1
In our example the Perl grep function loops over the keys of the main hash. At each iteration step, the current key is assigned in turn to the $_ special variable. Inside the grep block we test if the corresponding value of the price key of the corresponding inner hash is defined. If the expression within the grep block is evaluated true, the key stored in $_ is added to the @keys array.

Please note that when you use Perl defined with hash pair elements, this function will not report if a key exists but if the corresponding value of the key is defined. For example, if the second member of the %HoH hash is:

item2 => { quantity => 92, price => undef },
you’ll get as output the same result as before.

You can use the map function to access the elements of a Perl hash of hashes (%HoH).

Example 1.

You have a sample below:

#!/usr/bin/perl
 
use strict;
use warnings;
 
# initialize a hash of hashes
my %HoH = (
  1 => { name  => 'John', age => 20 },
  2 => { name  => 'Marry', age => 25 },
  3 => { name  => 'Patricia', age => 30 },
);
 
print map "$_->{name} ", values %HoH;
print "\n";

The Perl map function will loop through the values of the %HoH hash, assigning each value in turn to $_. In the $_ special variable we have a reference to the current inner hash and we need to dereference it by using the arrow operator (->).

The map function will return a list with the values associated with the name key in all inner hashes of the %HoH hash.

The output of this code is as following:

John Patricia Marry 

 

Example 2.

The following example shows you how to use two nested map to access and print a Perl hash of hashes (%HoH).

Please look at the following code snippet:

#!/usr/bin/perl
 
use strict;
use warnings;
 
# initialize a hash of hashes
my %HoH = (
  1 => { name => 'John', age => 20},
  2 => { name => 'Marry', age => 25},
  3 => { name => 'Patricia', age => 30},
);
 
# print the %HoA
my @result = map {
  my $outer = $_;
  $outer,
  ' => {',
  ( map {$_, ' => ', $HoH{$outer}{$_}, ', ' }
     keys %{$HoH{$outer}} ),
  "}\n"
} keys %HoH;
 
print @result;
The outer map loops over the keys of the outer hash while the inner map loops over the keys of the inner hashes. Because both map work with $_, you need to differentiate between the outer $_ and the inner $_. In this example the outer $_ is saved in the $outer scalar variable.

The elements returned by both map are saved in the @result array, which is printed.

The output is as follows:

    1 => {name => John, age => 20, }
    3 => {name => Patricia, age => 30, }
    2 => {name => Marry, age => 25, }

The following example shows you how to access and print the elements of a Perl hash of hashes (%HoH) using the while loop.

See the following code snippet:

#!/usr/bin/perl
 
use strict;
use warnings;
 
my %HoH = (
  1 => {name => 'John', age => 20},
  2 => {name => 'Marry', age => 25},
  3 => {name => 'Patricia', age => 30},
);
 
while (my ($keyo, $valo) = each %HoH) {
  print "$keyo => { ";
  while (my ($keyi, $vali) = each %{$valo}) {
    print "$keyi => $vali, ";
  }
  print "}\n";
}

The {} is the hash constructor and returns a reference to the anonymous hash enclosed in curly braces.

We use two nested Perl while loops - an outer while to loop over the outer hash and an inner while to loop over the inner hashes.

The outer while loop uses each to iterate through the %HoH hash. The each function returns the next pair element of the %HoH hash: the key in $keyo and the value (which is a reference to an anonymous hash) in $valo.

The inner Perl while loop uses each to iterate through the hash referenced by $valo. The each function returns the next pair element of the inner hash: the key in $keyi and the value in $vali.

The output of this script looks like this:

    1 => { name => John, age => 20, }
    3 => { name => Patricia, age => 30, }
    2 => { name => Marry, age => 25, }

In the following example I’ll show you how you can access, modify or add new elements to particular inner hashes. Finally, two nested foreach will help us to print the hash.

In our example, the Perl hash of hashes (%HoH) is at first the image of a matrix with 2 rows and 2 columns, and after we add a few members to inner hashes it will represent a matrix with 2 rows and 3 columns.

Here is the code:

#!/usr/local/bin/perl
 
use strict;
use warnings;
 
my %HoH = (
  1 => { 1 => '25', 2 => '17'},
  2 => { 1 => '83', 2 => '32'},
);
 
print "(row1, column2) = $HoH{1}{2}\n";
print "(row2, column1) = $HoH{2}{1}\n\n";
 
# modify the value of an element
$HoH{2}{2} = 99;
print "(row2, column2) = $HoH{2}{2}\n\n";
 
# add new elements
$HoH{1}{3} = 12;
$HoH{2}{3} = 54;
 
# print the %HoH
foreach my $k1 (sort keys %HoH) {
  foreach my $k2 (sort keys %{$HoH{$k1}}) {
    print "$HoH{$k1}{$k2}\t";
  }
  print"\n";
}
The output produced after running this script is as follows:

(row1, column2) = 17
(row2, column1) = 83
 
(row2, column2) = 99
 
25      17      12
83      99      54

To print the keys ordered I used the sort function.

If you have a Perl hash of hashes (%HoH) and you want to add a new anonymous hash to it, you can do it as in the following example:

#!/usr/local/bin/perl
 
use warnings;
use strict;
 
my %HoH = (
  France => {capital => 'Paris', language => 'french'},
  Italy => {capital => 'Rome', language => 'italian'}
);
 
$HoH {Romania} = {
 capital => 'Bucharest', language => 'romanian'
};
 
use Data::Dumper;
print Dumper \%HoH;
First, %HoH is populated with a few entries. Here {} is the hash constructor and return a reference to the anonymous hash included between braces.

Another way to add the anonymous hash is to simple write:

$HoH {Romania}{capital} = 'Bucharest';
$HoH {Romania}{language} = 'romanian';
To print the final %HoH, the Data::Dumper module is used:
 
$VAR1 = {
          'France' => {
                        'language' => 'french',
                        'capital' => 'Paris'
                      },
          'Italy' => {
                       'language' => 'italian',
                       'capital' => 'Rome'
                     },
          'Romania' => {
                         'language' => 'romanian',
                         'capital' => 'Bucharest'
                       }
        };

You can map the row of the matrix to a nested hash. The keys of the outer hash are the indices of the rows and the keys of the inner hashes are the indices of the columns.

We have to matrices, A and B and we intend to compute and print the matrix C where C = A + B, using the representation of a matrix as a Perl hash of hashes.

The elements of the A, B matrices are respectively contained in the @A, @B arrays (in order the elements of the first row, next the elements of the second row and last the elements of the third row).

      1 2 3         2 2 5         3 4 8

  A = 2 1 1     B = 0 1 2     C = 2 2 3

      3 1 1         2 1 3         5 2 4

Have a look at the following code:

#!/usr/local/bin/perl
 
use strict;
use warnings;
 
my @A = qw(1 2 3 2 1 1 3 1 1);
my @B = qw(2 2 5 0 1 2 2 1 3);
my (%A, %B, %C);
 
foreach my $i (1..3) {
  foreach my $j (1..3) {
    $A{$i}{$j} = $A[3 * ($i-1) + $j-1];
    $B{$i}{$j} = $B[3 * ($i-1) + $j-1];
    $C{$i}{$j} = $A{$i}{$j} + $B{$i}{$j};
  }
} 
 
use Data::Dumper;
print Dumper \%A;
 
# print the %C hash
foreach my $i (1..3) {
  foreach my $j (1..3) {
    print "$C{$i}{$j} ";
  }
  print "\n";
}
The output of this script is as follows:
 
$VAR1 = {
          '1' => {
                   '1' => 1,
                   '3' => 3,
                   '2' => 2
                 },
          '3' => {
                   '1' => 3,
                   '3' => 1,
                   '2' => 1
                 },
          '2' => {
                   '1' => 2,
                   '3' => 1,
                   '2' => 1
                 }
        };
3 4 8
2 2 3
5 2 4
 
I used the Data::Dumper module to print the %A hash of hashes to see its elements. The %C hash of hashes is printed using two nested foreach.

An arbitrary ij element of the A matrix can be accessed from the %A hash of hashes by using the notation: $A{$i}{$j}where $iand  $j are respective the line and the column of the matrix and both have values between 1 and 3 (for a matrix with 3 rows and 3 columns).

You can easily extend this example for quadratic matrices with more than 3 rows and 3 columns.

I’ll examine below the Perl hash of hashes length, by which I mean the length in bytes of all the hash values.

Because the values of the hash are references to other hashes, we need to find the length of these inner hashes too.

For computing the hash length I’ll use the Perl length function which returns the number of characters of an expression.

If you’ll use Unicode characters in your hash values, the number of characters may be different from the number of bytes.

Let’s examine the following example:

#!/usr/bin/perl
 
use warnings;
use strict;
 
# initialize a hash of hashes
my %HoH = (
 item1 => { color => 'red', shape => 'round'},
 item2 => { color => 'yellow', shape => 'rectangle'},
 item3 => { color => 'blu', shape => 'square'}
);
 
# using the length() function
{
  use bytes;
  my $count = 0;
 
  foreach my $oKey ( keys %HoH ) {
    foreach my $iKey ( keys %{ $HoH{$oKey} } ) {
      $count += length( $HoH{$oKey}{$iKey} );
    }
  }
  print "Perl HoH length (through length() function) is: ",
      $count, "\n";
}
The output:
 
Perl HoH length (through length() function) is: 32
 
%HoH is a 2-dimensional hash (or a hash of hashes) and the code snippet shown above will get us the length in bytes of the %HoH hash. I used the use bytes pragma, and I put the snippet code in a block {} in order to limit the effect of this pragma to the scope in which it appears, i.e. inside the block.

I populated the %HoH hash with three pair elements having as keys item1, item2 and item3. Each key has associated as value a reference to an anonymous hash, the {} is the hash constructor and returns a reference to an anonymous hash.

To compute the length of the values of the %HoH aggregate, I used two nested Perl foreach loops. In the outer foreach loop, I iterate over the elements of the outer hash, and in the inner foreach loop I iterate over the inner hashes.

The keys function returns a list with the keys of the outer/inner hash. $oKey is the current key of the outer hash and $HoH{$oKey} is its associated value that is a reference to the inner corresponding hash. To dereference the inner hash reference, you need to precede the hash reference with the % symbol. The $HoH{$oKey}{$iKey} is the current value of an element that belongs to the inner hash and is associated with $iKey.