How to deal with arrays of hashes - Part 2

To remove the first element of an @AoH (array of hashes) you can use the shift function. But keep in mind that because each element of the @AoH array is a reference to a hash, after shift deletes and returns the reference, the hash is still in memory, only the reference is removed.

To entirely remove the first element and the hash referenced by it you can use the following syntax form:

%{shift @AoH} = ();
The shift function returns and removes the first element of the @AoH (array of hashes). The % symbol is used to dereference the hash reference returned by the shift function.

Next the inner hash is initialized with an empty list. See the following code for an example:

#!/usr/local/bin/perl
 
use strict;
use warnings;
 
my @AoH = (
 {name => 'John', age => '21'},
 {name => 'Paul', age => '35'},
 {name => 'Mary', age => '50'},
);
 
# remove the first element of @AoH and clear the hash
%{shift @AoH} = ();
 
# print the @AoH
foreach my $href ( @AoH ) {
 print "$href->{name} is $href->{age} years old.\n";
}
This code produces the following output:
 
    Paul is 35 years old.
    Mary is 50 years old.

To print the array of hashes, the foreach loop was used. Please note the ->{} arrow notation, used to access the elements of a hash table given by a reference.

If you want to save the element removed (the first inner hash), you can use the following syntax form:

my $hashRef = shift @AoH;

You can use the pop function to remove the last element of an @AoH array of hashes, but because the last element of the @AoH array is a reference to a hash, after pop deletes the element, the hash is still in memory, only the reference was removed. To entirely remove the last element and the hash referenced by it you can use the following syntax form:

%{pop @AoH} = ();
The pop function returns and removes the last element of the @AoH (Perl array of hashes). The % symbol is used to dereference the hash reference returned by the pop function. Next the inner hash is initialized with an empty list. See the following code for an example:
 
#!/usr/local/bin/perl
 
use strict;
use warnings;
 
my @AoH = (
  {name => 'John', age => '21'},
  {name => 'Paul', age => '35'},
  {name => 'Mary', age => '50'},
);
 
# remove he last element of @AoH and clear the hash
%{pop @AoH} = ();
 
# print the @AoH
print join "\n",
     map {$_->{name}." is ".$_->{age}." years old."} @AoH;
print "\n";
This code produces the following output:
 
John is 21 years old.
Paul is 35 years old.
 
To print the array of hashes, the join and map functions were used. Please note the usage of the . concatenation operator here and the ->{} arrow notation, used to access the elements of a hash table given by a reference.

As you know, a Perl array of hashes (@AoH) is an array whose values are references to hashes. In the following example I’ll show you how to delete a particular inner hash entry, by using the delete function.

Here is the snippet:

#!/usr/local/bin/perl
 
use strict;
use warnings;
 
my @AoH = (
 {k00 => 'v00'},
 {k10 => 'v10', k11 => 'v11'},
 {k20 => 'v20', k21 => 'v21', k22 => 'v22'},
);
 
# delete a particular inner hash entry
delete $AoH[1]{'k11'};
 
# print the @AoH array 
 
foreach my $item ( @AoH ){
 foreach my $key ( keys %{ $item } ){
   print "$key=$item->{ $key }\t"; 
 }
 print "\n";
}
First, I populated the @AoH Perl array of hashes with a few entries. This array has three elements, each element being a reference to an anonymous hash. To create references to anonymous hashes, the {} hash constructor was used.

To delete a particular inner hash entry we used the following code line:

delete $AoH[1]{'k11'};
Here 1 means the index of the array and 'k11' is the key that we want to remove from the hash referenced by the element of index 1 of the array.

This code produces the following output:

k00=v00
k10=v10
k20=v20 k21=v21 k22=v22

Look at the following code:

# delete the inner hashes
%{$_} = () foreach (@AoH);
 
# clear the array
@AoH = ();
To clear the Perl @AoH array of hashes, first you need to free the memory occupied by the inner hashes. This is done by using the foreach loop to traverse the @AoH array of hashes. At each iteration step, the current element of the array is assigned in turn to $_.

Thus in $_ we have a reference to an inner hash, to clear the hash you need to assign an empty hash to it: %{$_} = () (the %{} notation is used to dereference the hash reference).

An alternative is to assign an empty hash reference to the hash reference: $_ = {}. Please note that here {} means the hash constructor which returns a hash reference.

To see the content of the array of hashes after the clearing operation, you can use the Data::Dumper module:

use Data::Dumper;
print Dumper(\@AoH);

You can use unshift to insert an element to the first position of an @AoH array of hashes, by using the following syntax form:

unshift @AoH, $hashRef;
where $hashRef is a reference to a specific hash.

See the following code for an example:

#!/usr/local/bin/perl
 
use strict;
use warnings;
 
my @AoH = (
 {name => 'John', age => '21'},
 {name => 'Paul', age => '35'}, 
);
 
# insert a new element to @AoH
unshift @AoH, { name => 'Mary', age => '50' };
 
# print the @AoH
print join "\n",
     map {$_->{name}." is ".$_->{age}." years old."} @AoH;
print "\n";
This code produces the following output:
 
    Mary is 50 years old.
    John is 21 years old.
    Paul is 35 years old.

The {} hash constructor is used to return a reference to the hash enclosed between curly brackets.

To print the Perl array of hashes, the print, join and map functions were used.

Please note the usage of the . concatenation operator here and the ->{} arrow notation, used to access the elements of a hash table given by a reference.

To append an element to an @AoH array of hashes you can use the push function with the following syntax form:

push @AoH, $hashRef;
where $hashRef is a reference to a hash.

See the following code for an example:

#!/usr/local/bin/perl
 
use strict;
use warnings;
 
my @AoH = (
 {name => 'John', age => '21'},
 {name => 'Paul', age => '35'}, 
);
 
# add a new element to @AoH
push @AoH, { name => 'Mary', age => '50' };
 
# print the @AoH
print join "\n",
     map {$_->{name}." is ".$_->{age}." years old."} @AoH;
print "\n";
This code produces the following output:
 
    John is 21 years old.
    Paul is 35 years old.
    Mary is 50 years old.

The {} hash constructor is used to return a reference to the hash enclosed between curly brackets.

To print the array of hashes, the print, join and map functions were used.

Please note the usage of the . concatenation operator here and the ->{} arrow notation, used to access the elements of a hash table given by a reference. 

The following example uses splice to remove a few elements of a Perl array of hashes and to replace them with the elements stored in another array of hashes.

In the following code, we replace the second element of the @AoH array of hashes with the elements stored in the @tempAoH array of hashes.

Please note that the elements of both arrays are references to anonymous hashes.

See the code:

#!/usr/local/bin/perl
 
use strict;
use warnings;
 
my @AoH = (
 {name => 'John', age => '21'},
 {name => 'Paul', age => '35'},
 {name => 'Mary', age => '50'},
);
 
my @tempAoH = (
 {name => 'Anne', age => '32'},
 {name => 'Ken', age => '19'},
);
 
splice @AoH, 1, 1, @tempAoH;
 
# print the @AoH
foreach my $href ( @AoH ) {
 print "$href->{name} is $href->{age} years old.\n";
}
print "\n";
The output is as follows:

    John is 21 years old.
    Anne is 32 years old.
    Ken is 19 years old.
    Mary is 50 years old.

Please note that the splice function replaced only the references so the anonymous hash referenced by the initial second element of the @AoH array is still in memory.

For the same reason, you can’t clear the anonymous hashes referenced by the elements of the @tempAoH array because the references to these hashes are stored in the resulting @AoH array.

If you need to release the memory occupied by the anonymous hashes that were replaced, please recall that the splice function in a list context returns the list of the elements removed from the array.

You can use the following lines of code to accomplish this:

my @list = splice @AoH, 1, 1, @tempAoH;
%$_ = () foreach (@list);
@list = ();
The foreach loop steps through the elements of the @list, assigning in turn each element to $_.

The % symbol is used to dereference the hash reference stored in $_. Or a more concise code (if you want):

%$_ = () foreach(splice @AoH, 1, 1, @tempAoH);
If you only want to remove the second element of the @AoH array, you can use the following syntax:
 
%$_ = () foreach(splice @AoH, 1, 1);
If you print the @AoH array, you’ll get as result:
 
John is 21 years old.
Mary is 50 years old.

A Perl array of hashes (@AoH) is an array that has as elements references to hashes.

To copy an array of hashes into a new one there are two ways:

A shallow copy – it assumes to copy the content of the array of hashes into a new array. You can do this by a simple assignment, as you can see below:

my @newAoH = @AoH;
Please note that by using this method you just copy the references from @AoH into @newAoH.

The two arrays will share the inner hashes, in such a way that if you change the content of an inner hash, both @AoH and @newAoH are changed as they both point to the same anonymous hash.

A deep copy – it assumes to copy the references and the content of the inner hashes too. In this case the references will point to different memory locations.

The following example shows you how to use a recursive subroutine to copy each of the data contained in the Perl array of hashes:

#!/usr/local/bin/perl
 
use strict;
use warnings;

my @AoH = (
 {name => 'John', age => '21'},
 {name => 'Paul', age => '35'},
 {name => 'Mary', age => '50'},
);

my @newAoH = clone(@AoH);

# for the second array alter the value corresponding
# to the 'age' key

$AoH[1]{age} = 71;

sub clone {
 map { ! ref() ? $_ : {clone(%$_)} } @_;
}

# print the @AoH
print "\@AoH:\n";
print join "\n",
     map {$_->{name}." is ".$_->{age}." years old."} @AoH;
print "\n";

# print the @newAoH
print "\n\@newAoH:\n";
print join "\n",
     map {$_->{name}." is ".$_->{age}." years old."} @newAoH;
print "\n";
The output is as follows:
 
    John is 21 years old.
    Paul is 71 years old.
    Mary is 50 years old.

    @newAoH:
    John is 21 years old.
    Paul is 35 years old.
    Mary is 50 years old.

In this example we use the clone() subroutine to copy all the elements of our Perl array of hashes.

Inside the body of the subroutine we use the Perl map function that loops through @_ (the special @_array has as elements the values passed to the subroutine). At each iteration step the current element of the @_array is assigned in turn to $_.

Inside the map block the ? ternary operator and the ref function are used to test if an element of @_ array is a reference.

The map function will return:

  • the value stored in $_ if this value is not a reference, otherwise
  • a reference to a new independent anonymous hash created by the {} hash constructor; in the same time we need to call the subroutine again to copy the elements of the hash referenced by $_

After the array was duplicated, in @AoH array we altered the content of the second array element: in the anonymous hash referenced by this element, the value corresponding to the age key was assigned to 71.

As you can see from the output, the contents of the two arrays are different, the @newAoH array haven’t been affected by this modification.

For more complicated structures you can use the Storable module which provides the dclone function that allows you to do recursively copies too (See perlfaq4). 

Let’s say you have a Perl array of hashes (@AoH) and you want to use it within a subroutine. A common way to do this is by passing the array of hashes by reference.

See a simple example below:

#!/usr/local/bin/perl
 
use strict;
use warnings;
 
my @AoH = (
 {a11 => 23, a12 => 17}, 
 {a21 => 45, a22 => 99},
);
 
# invoke the subroutine
myPrint(\@AoH);
 
sub myPrint{
 my $arrayRef = shift;
 
 foreach my $item1 ( @$arrayRef ){
   while(my ($key, $val) = each % {$item1}) {
     print("$key => $val\t");
   }
   print "\n";
 }
}
This script produces the following output:

    a12 => 17 a11 => 23
    a22 => 99 a21 => 45

First we populate the @AoH Perl array of hashes with a few entries.

The {} is the hash constructor and returns a reference to an anonymous hash whose elements are included between braces.

The myPrintsubroutine is used to print the Perl array of hashes. It has as argument a reference to an array of hashes.

Inside the subroutine body we use the shift function to discharge the argument, assigning it to the $arrayRef scalar variable. So in $arrayRef we have a reference to our array of hashes.

To dereference the array reference, we prefix them with an @ sign and to dereference the inner hash references we prefix the reference with a % sign.

The foreach statement is used to loop through the elements of the array of hashes. To loop through the inner hashes, we used while and each.

If you need to get the inner hashes sorted in some way, you need to replace the while loop with foreach, you have an example here:

 foreach my $item2 ( sort keys %$item1) {
   print("$item2 => $item1->{$item2}\t");
 }
and the appropriate output:
 
a11 => 23 a12 => 17
a21 => 45 a22 => 99

In a similar way you can modify the subroutine and write your own code in order to perform inside its body whatever you need.

In a Perl array of hashes (@AoH), you can use the exists function to avoid autovivification when you don’t intend to use it.

See the following example:

#!/usr/local/bin/perl
 
use strict;
use warnings;
 
my @AoH = (
 {a11 => 23, a12 => 17, a13 => 100}, 
 {a21 => 45, a22 => 99},
);
 
# autovivification
$AoH[2]{a33} = 75; 
defined $AoH[3]{a42} || print "not found\n";
 
use Data::Dumper;
print Dumper \@AoH;
First we populate a Perl array of hashes with a few entries. An array of hashes is an array whose values are references to hashes. To get references to anonymous hashes, the {} hash constructor was used.

Now let’s pay a bit of attention to this code.

The first assignment statement:

$AoH[2]{a33} = 75;
adds an entry to our array of hashes. Because $AoH[2] doesn’t exist it will be created with an appropriate value, so you don’t need to create yourself the inner hash ($AoH[2] = {}). This process is called autovivification and it is very useful when you have to deal with this kind of assignments. The expression can be arbitrary complicated and Perl will create all the structures it needs to make the assignment.

But if you look at the following statement:

defined $AoH[3]{a42} || print "not found\n"; 
first it will be evaluated the defined $AoH[3]{a42} expression and because the result is false the print function will be executed. But in the process of evaluation Perl needs to create the $AoH[3] element which will remain as a reference entry to an empty inner hash – see the output. This time the process of autovivification enlarged our @AoH structure with an unnecessary entry.

Please note the using of || short-circuit operator that evaluates the second operand only if the first operand is evaluated false.

To see what is happening, I printed the hash using the Data::Dumper module. The output of this script is as follows:

$VAR1 = [
          {
            'a12' => 17,
            'a11' => 23,
            'a13' => 100
          },
          {
            'a22' => 99,
            'a21' => 45
          },
          {
            'a33' => 75
          },
          {}
        ];
 
As you can see our array was enlarged with a new element - an empty hash reference.

As I mentioned at the beginning of this script, to avoid autovivification in this last case, you can use the exists function:

if(exists $AoH[3] && defined $AoH[3]{a42}) {
 print "found\n"; 
}
First we test if $AoH[3] exists and only afterwards we check if $AoA[3]{a42} is defined.

Please note the using of && short-circuit operator that evaluates the second operand only if the first operand is evaluated true.