Perl Hash

extern: index
intern: preamble | hash | reference | sample | copy hash | modify | delete | end

Preamble

A Perl HASH, or 'associative array', is a FASCINATING beast ... and this page contains some example ...


top

Hash - Associative Arrays

To declare a hash, use '%', and to clear the hash ...

code:

my %hash1 = ();

To declare a hash with elements ... I always think of it as a 'key' pointing to a 'value' ...

code:

my %hash1 = (
   'key1' => 'key1 Value',
   'key2' => 'key2 Value',
   'key3' => 'key3 Value' );

To get the count of elements in a hash ...

code:

my $cnt = scalar keys %hash1;
print "Got $cnt keys in \%hash1 ...\n";

output:

Got 3 keys in %hash1 ...

To enumerate the keys, and values, you can use the following ... note the use of the scalar '$' and the curly brackets, { } ... also note the order is not necessarily as declared! ...

code:

foreach my $key (keys %hash1 ) {
   print $key.' has value ['. $hash1{$key} ."]\n";
}

output:

key2 has value [key2 Value]
key1 has value [key1 Value]
key3 has value [key3 Value]

To establish some order, the array of keys returned by 'keys %hash1' can be sorted ...

code:

my @arr = keys %hash1;
foreach my $key ( sort @arr ) {
   print $key.' has value ['. $hash1{$key} ."]\n";
}

output:

key1 has value [key1 Value]
key2 has value [key2 Value]
key3 has value [key3 Value]

Another example - With a HASH, like the following, with the subs shown, and then a test output ... Note the return of a hash reference, and how the members of that hash reference can be accessed ...

code:

#!/Perl
# testiso2.pl - 2006.08.28
# ISO' => 'Country'
my %CurrencyISO = (
'AED' => 'United Arab Emirates Dirhams',
'AUD' => 'Australia Dollars',
'AWG' => 'Aruba Guilders',
'BBD' => 'Barbados Dollars',
'BMD' => 'Bermuda Dollars' );
print "test ISO to Currency ...\n";
print "ISO AWG = ".ISO2Currency('AWG')."\n";
print "test Currency to ISO ...\n";
my $ref_test = Currency2ISO('dollar');
my $cnt = keys %$ref_test;
if ($cnt) {
   while (my ($k, $v) = each %$ref_test) {
      print "ISO [$k] => [$v]\n";
   }
  } else {
   print "FAILED\n";
  }
exit(0);
sub ISO2Currency {
   my ($iso) = shift;
   my $v = '';
   foreach my $k (keys %CurrencyISO) {
      if ($k eq $iso) {
         $v = $CurrencyISO{$k};
         return $v;
      }
   }
   return "NOT FOUND $iso";
}

sub Currency2ISO {
   my ($cur) = shift;
   my %aa = ();
   my $v = '';
   foreach my $k (keys %CurrencyISO) {
      $v = $CurrencyISO{$k};
      if ($v =~ /$cur/i) {
         ###print "Added [$k] [$v]\n";
         $aa{$k} = $v;
      }
   }
   return \%aa;     # return a reference
}
# end testiso2.pl

output:

test ISO to Currency ...
ISO AWG = Aruba Guilders
test Currency to ISO ...
ISO [BBD] => [Barbados Dollars]
ISO [AUD] => [Australia Dollars]
ISO [BMD] => [Bermuda Dollars]

Then there are times we might want the HASH to contains references to anonymous arrays, like - note the special [...] notation to cause a COPY of the array to be stored in the HASH ...

code:

#!/Perl
# Sometimes we may want a hash to contain a COPY of an array (as a reference)
# and NOT refer back to the original array variable.
my %hash = ();
my ($aref);
my $conf1 = 'proj|Debug';
my $conf2 = 'proj|Release';
my $item1 = 'defines=[/D "NDEBUG"]';
my $item2 = 'outputs=[".\Release"]';
my $item1d = 'defines=[/D "_DEBUG"]';
my $item2d = 'outputs=[".\Debug"]';
my @arr = ();
# add debug items
@arr = ();  # clear the array
push(@arr,$item1d);
push(@arr,$item2d);
# store reference
$aref = \@arr;
$hash{$conf1} = [@{$aref}]; # add COPY of the array
# add release items
@arr = ();  # clear the array
push(@arr,$item1);
push(@arr,$item2);
$aref = \@arr;
$hash{$conf2} = [@{$aref}]; # add COPY of the array
foreach my $key (keys %hash) {
    #print $hash{$key}." "; # this would just print ARRAY(0xaddress)
    print "$key => ";
    my $ar2 = $hash{$key};  # extract the reference 
    foreach my $itm (@{$ar2}) { # iterate the reference
        print "$itm ";
    }
    print "\n";
}

output:

proj|Release => defines=[/D "NDEBUG"] outputs=[".\Release"]
proj|Debug => defines=[/D "_DEBUG"] outputs=[".\Debug"]

Also note the special notation to address the members of an array reference, like @{$ar2}...

In a more 'complex' situation, where a 'hash' is to be copied to, and returned in another hash, inside an array - I wanted to return 'lots' of information in one hash ... this example built from the good information contained in -
 http://www.cs.mcgill.ca/~abatko/computers/programming/perl/howto/hash/ - a great page about hashes ...

code:

#!perl -w
use strict;
use warnings;
my %hash = get_hash();
show_hash(\%hash);
exit(0);
sub show_hash {
    my ($hr) = @_;  # get the hash reference
    my ($key, $val, $cnt, $i, $src, $h2r, $msg, $k, $v);
    prt( "Show hash (reference) contents ...\n" );
    foreach $key (keys %{$hr}) {
        $val = $$hr{$key};
        if ($key eq 'C_SOURCES') {
            $cnt = scalar @{$val}; # this is an array
            prt( "Got $cnt sources ...\n" );
            for ($i = 0; $i < $cnt; $i++) {
                $src = $$val[$i][0];
                $h2r = $$val[$i][3];    # this is a hash reference
                $msg = "$src ";
                foreach $k (keys %{$h2r}) {
                    $v = $$h2r{$k};
                    $msg .= " [$k = $v]";
                }
                prt( "$msg\n" );
            }
        } else {
            prt( "$key = $val\n" );
        }
    }
}
sub get_hash {
    my %h = ();
    my @srcs = ();
    my $hr;
    $h{'-NEW_RT_DBG'} = '/MDd';
    $h{'-NEW_RT_REL'} = '/MD';
    $hr = {};   # clear the hash reference
    $hr->{'debug'} = 'Debug';       # add some values
    $hr->{'release'} = 'Release';
    push(@srcs, ["file1.c", "group", "filter", $hr]); # store it
    $hr = {};   # clear reference
    $hr->{'debug2'} = 'Debug/Dupe'; # add some other values
    $hr->{'release2'} = 'Release/Dupe';
    push(@srcs, ["file2.c", "group", "filter", $hr]); # store it
    $h{'C_SOURCES'} = [@srcs];  # copy the array into the hash
    return %h;
}
sub prt {
    my ($txt) = shift;
    print $txt;
}
# eof

output:

Show hash (reference) contents ...
-NEW_RT_DBG = /MDd
Got 2 sources ...
file1.c  [debug = Debug] [release = Release]
file2.c  [debug2 = Debug/Dupe] [release2 = Release/Dupe]
-NEW_RT_REL = /MD

Note such things as the clearing of the hash reference $hr = {};, the setting of values into the hash reference $hr->{'debug'} = 'Debug', the copying of the hash reference into the array push(@srcs, ['file1.c',...,$hr]);, copying of the array into the hash $h{'C_SOURCES'} = [@srcs];, and how to extract, and enumerate the members of the hash reference ...

top -|- index -|- samples


Sample

You can create a reference to an anonymous array or hash by using square brackets for an array and braces for a hash:

code:

my $array_ref = ['apple', 'banana', 'orange'];
my $hash_ref = {name => 'Becky', age => 23};

You can store an anonymous function in a hash, and call that function by:.

code:

#!perl -w
use strict;
use warnings;
my %hash = (frogs => sub {print "Hello, World...\n"});
&{ $hash{frogs} }();

output:

Hello, World...

top

Copy A Hash

Use $master{$key} = { %hash } to COPY a hash:

code:

#!/bin/perl
# NAME: copyhoh.pl
# AIM: copy a hash, into a hash reference, as the value
use strict;
use warnings;
my %collection = ();
sub prt($) { print shift; }
sub gen_hash($) {
    my ($hr) = shift;
    my %items = ();
    my ($i, $j, $i2, $j2, $key2, $val2, $key1);
    for ($j = 0; $j < 3; $j++) {
        $j2 = $j + 1;
        %items = ();        # clear the hash
        $key1 = "KEY$j2";
        for ($i = 0; $i < 3; $i++) {
            $i2 = $i + 1;
            $key2 = "key".($j2 * $i2);
            $val2 = "value".($j2 * $i2);
            $items{$key2} = $val2;  # generate an item
        }
        $$hr{$key1} = { %items };   # COPY the HASH, into a HASH REF, as the value
    }
}
sub show_collection($) {
    my ($hr) = shift;
    my $max = scalar keys %$hr;
    prt( "Got $max keys...\n" );
    foreach my $key1 (sort keys %$hr) {
        my $val1 = $$hr{$key1};
        foreach my $key2 (sort keys %$val1) {
            my $val2 = $$val1{$key2};
            prt( "$key1: $key2 = $val2\n" );
        }
    }
}
gen_hash( \%collection );
show_collection( \%collection );
exit 0;
# eof - copyhoh.pl

output:

Got 3 keys...
KEY1: key1 = value1
KEY1: key2 = value2
KEY1: key3 = value3
KEY2: key2 = value2
KEY2: key4 = value4
KEY2: key6 = value6
KEY3: key3 = value3
KEY3: key6 = value6
KEY3: key9 = value9

top -|- index -|- samples

Modify a Hash

A reference hash can be modified, including adding the contents of an 'anonymous' hash...

code:

#!/usr/bin/perl -w
use strict;
use warnings;
use Data::Dumper;
my %hash = ( 'key1' => 'val1', 'key2' => 'val2' );
sub get_hash_of_hash {
    my ($rh) = @_;
    my $tot = 0;
    foreach my $key (keys %{$rh}) {
        my $val = ${$rh}{$key}; # get current value
        $tot++;
        my %h = ();  # build up an anonymous hash
        for (my $i = 0; $i < 2; $i++) {
            my $k2 = "KEY$i$tot";
            my $v2 = "VAL$i$tot";
            $h{$k2} = $v2; # store this
        }
        ${$rh}{$key} = [$val, \%h]; # and then 'ADD' this 'anonymous' hash,
        # together with the original value into an array reference
    }
    return $rh;
}
my $refh = \%hash;   # conver to REFERENCE
print "Dump of original...\n";
print Dumper($refh); # show original value
my $rnh = get_hash_of_hash( $refh );   # modify, adding a generated hash
print "Dump of modified...\n";
print Dumper($rnh);  # show the results
# eof

output:

Dump of original...
$VAR1 = {
          'key2' => 'val2',
          'key1' => 'val1'
        };
Dump of modified...
$VAR1 = {
          'key2' => [
                      'val2',
                      {
                        'KEY01' => 'VAL01',
                        'KEY11' => 'VAL11'
                      }
                    ],
          'key1' => [
                      'val1',
                      {
                        'KEY12' => 'VAL12',
                        'KEY02' => 'VAL02'
                      }
                    ]
        };

So the old value, be it a string, or and array ref, or what ever, and new hash (ref) are stored in an array reference in the original hash, replacing the old value... simple ;=))


top -|- index -|- samples

Delete Hash Entries

A hash entry can be delete, using 'delete'

code:

my %hash = ( 'a' => 1, 'b' => 2, 'c' => 3 );
my @arr = qw( a b c );
foreach my $key (@arr) {
     if (defined $hash{$key}) {
         delete $hash{$key};
     }
}
if (scalar keys(%hash) == 0) {
     prt("All deleted... ok\n");
} else {
     prt("Deletion FAILED\n");
}

output:

All deleted... ok

top -|- index -|- samples

References

This is just some reference pages seen...

http://www.cs.mcgill.ca/~abatko/computers/programming/perl/howto/hash/
 


top -|- index -|- samples

And that's it for now...

EOF - perl_hash.htm

checked by tidy  Valid HTML 4.01 Transitional