Home Guest Book | Technical PagePersonal Page

Perl HASH
 
About Me
Who is a Good QA
Latest News
Testing Concepts
Automation Tools
Agile Development
UNIX Basics
Perl Scripting
MySQL
Technology
Repository
Imp. Commands
My Resume


Perl Hash Howto

This howto comes with no guaratees other than the fact that these code segments were copy/pasted from code that I wrote and ran successfully.

Initialize clear, or empty) a hash.

Assigning an empty list is the fastest method.

Solution

    my %hash = ();

Note

People have asked how to initialize a hash reference (aka hash ref). It's just like any scalar variable; you can use my alone, or you can assign a value.

    my $hash_ref;
    my $hash_ref = 0;  # zero

Copy a hash.

Solution

    my %hash_copy = %hash;  # copy a hash

    my $href_copy = $href;  # copy a hash ref

Delete a single key/value pair.

The solution differs for a hash and a hash reference, but both cases can use the delete function.

Solution

Hash:

    delete $hash{$key};

Hash reference:

    delete $hash_ref->{$key};

Perform an action on each key/value pair in a hash.

The actions below print the key/value pairs.

Solution

Use each within a while loop. Note that each iterates over entries in an apparently random order, but that order is guaranteed to be the same for the functions keys and values.

    while ( my ($key, $value) = each(%hash) ) {
        print "$key => $value\n";
    }

A hash reference would be only slightly different:

    while ( my ($key, $value) = each(%$hash_ref) ) {
        print "$key => $value\n";
    }

Solution

Use keys with a for loop.

    for my $key ( keys %hash ) {
        my $value = $hash{$key};
        print "$key => $value\n";
    }

Example

    my $file = $ARGV[0] || "-";

    my %from = ();

    open FILE, "< $file" or die "Can't open $file : $!";

    while( <FILE> ) {
        if (/^From: (.*)/) { $from{$1}++ }  # count recurrences of sender
    }

    close FILE;

    for my $sender ( sort keys %from ) {
        print "$sender: $from{$sender}\n";
    }

Get the size of a hash.

Solution

    print "size of hash:  " . keys( %hash ) . ".\n";

Solution

    my $i = 0;

    $i += scalar keys %$hash_ref;  # method 1: explicit scalar context
    $i += keys %$hash_ref;         # method 2: implicit scalar context

Use hash references.

Solution

    sub foo
    {
        my $hash_ref;

        $hash_ref->{ 'key1' } = 'value1';
        $hash_ref->{ 'key2' } = 'value2';
        $hash_ref->{ 'key3' } = 'value3';

        return $hash_ref;
    }

    my $hash_ref = foo();

    print "the keys... ", sort keys %$hash_ref, "...\n";

Function to build a hash of hashes; return a reference.

Solution

    sub foo
    {
        my ( $login, $p, $uid, $gid, $gecos, $dir, $s );

        my %HoH = ();

        my $file = '/etc/passwd';
        open( PASSWD, "< $file" ) or die "Can't open $file : $!";

        while( <PASSWD> ) {
            ( $login, $p, $uid, $gid, $gecos, $dir, $s ) = split( ':' );

            $HoH{ $login }{ 'uid' } = $uid;
            $HoH{ $login }{ 'gid' } = $gid;
            $HoH{ $login }{ 'dir' } = $dir;
        }

        close PASSWD;

        return \%HoH;
    }

Access and print a reference to a hash of hashes.

Solution

    my $rHoH = foo();

    my( $uid, $gid, $dir );

    for my $login ( keys %$rHoH ) {

        $uid =       $rHoH->{ $login }->{ 'uid' };   # method 1  most readable
        $gid =    ${ $rHoH->{ $login } }{ 'gid' };   # method 2
        $dir = ${ ${ $rHoH }{ $login } }{ 'dir' };   # method 3 least readable

        print "uid: $uid, gid: $gid, dir, $dir.\n";
    }

Solution

    my $rHoH = foo();

    for my $k1 ( sort keys %$rHoH ) {
        print "k1: $k1\n";
        for my $k2 ( keys %{$rHoH->{ $k1 }} ) {
            print "k2: $k2 $rHoH->{ $k1 }{ $k2 }\n";
        }
    }

Function to build a hash of hashes of hashes; return a reference.

Solution

    sub foo
    {
        my %HoHoH = ();

        while( ... ) {

            if( /LOCATION:/ ) {

                ...

            } elsif( /MODULE:/ ) {

                $HoHoH{ $loc }{ $module_type }{ MODULE_NAME } = $module_name;

            } elsif( $ARGS_ALLOWED ) {

                $HoHoH{ $loc }{ $module_type }{ $arg_name } = $arg_value;

            }

        }

        return \%HoHoH;
    }

Access and print a reference to a hash of hashes of hashes.

Solution

    my $rHoH = foo();

    for my $k1 ( sort keys %$rHoHoH ) {
        print "$k1\n";

        for my $k2 ( sort keys %{$rHoHoH->{ $k1 }} ) {
            print "\t$k2\n";

            for my $k3 ( sort keys %{$rHoHoH->{ $k1 }->{ $k2 }} ) {
                print "\t\t$k3 => $rHoHoH->{ $k1 }->{ $k2 }->{ $k3 }\n";
            }
        }
    }

Print the keys and values of a hash, given a hash reference.

Solution

    while( my ($k, $v) = each %$hash_ref ) {
        print "key: $k, value: $v.\n";
    }

Determine whether a hash value exists, is defined, or is true.

Solution

    print "Value EXISTS, but may be undefined.\n" if exists  $hash{ $key };
    print "Value is DEFINED, but may be false.\n" if defined $hash{ $key };
    print "Value is TRUE at hash key $key.\n"     if         $hash{ $key };

Example

Let's say we execute an sql query where some of the resulting values may be NULL. Before attempting to use any of the values we should first check whether they are defined, as in the following code. Note that the subroutine sql_fetch_hashref() takes care of connecting to the database, preparing the statement, executing it, and returning the resulting row as a hash reference using DBI's fetchrow_hashref() method.

    my $answers = 'a,b,c,d,e';

    my $sql = "select max_time, $answers from questions " .
              'where question_number=?';
    my $hash_ref = sql_fetch_hashref( $sql, $q );

    my @answers = split ',', $answers;

    my $max_time = $hash_ref->{max_time} || '60';

    my $hash_ref_ans;
    for my $letter ( @answers ) {
        $hash_ref_ans->{ $letter } = $hash_ref->{ $letter }
            if defined $hash_ref->{ $letter };
    }

The for loop made a new hash of only defined key/value pairs.


How to make hash of array

$Hash{$key} = \@Array -> @Array = @{$Hash{$key}}

 

Author of this page:

KUNAL SAXENA

 

 

 

More on HASH

the hash structure is based upon a Perl hash table that associates keys with values

 

One-dimensional hashes

 

 

By one-dimensional Perl hash or simple hash we generally mean a hash whose elements are not references to other Perl structures (arrays or hashes). See %ages and %members hashes shown below for an example:

%ages = ("John", 43, "Paul", 25, "Marie", 22);

%members = (John => "father", Paul => "son",

                        Marie => "daughter");

 

Copy a hash

 

%destHash = %sourceHash;  # copy a hash

$destHasRef = $sourceHashRef;  # copy a hash ref

This is a shallow method to copy Perl hashes, and works well when we speak about oneĖdimensional hashes, with no references to other structures.

Create or initialize a hash



Perl hashes are structures and you do not need to allocate structures or other variables in Perl. The first time you use a hash type variable in your code, that variable will be automatically created. Please look at the following code:

%ages = ("John", 43, "Paul", 25, "Marie", 22);

%members = (John => "father", Paul => "son",

                      Marie => "daughter");

$agesRef = \%ages;

print $$agesRef{Marie}; #prints 22

In the above example, we used two ways to create/initialize a hash variable. In the first line we initialized the %ages hash variable with a list composed by pairing of keys and values, separated by commas. But Perl has a special "comma-arrow" (=>) operator that we used to initialize the %members hash variable in the second line of code. The left side of the comma-arrow operator is expected to be a simple string and therefore it is not necessary to be quoted.

The third line shows you how to define a hash reference in Perl. You can dereference Perl hashes using the notation %$hashRef. If you want to get a certain hash value, you can dereference it by using the notation $$hashRef{key} Ė the fourth line of the above snippet code shows you how to do that.

Iíll show you below the Perl hash table for both the %ages and %members hash variables.

%ages

key

value

John

43

Paul

25

Marie

22

%members

key

value

John

father

Paul

son

Marie

aughter

 

Empty or clear a hash



In order to initialize Perl hashes to an empty list, you can use the code line:

%hash = ();

 

Extract slices from a hash



Perl lets you extract slices from Perl hashes. Please look at the following code:

# define a hash

%cds = ("Dr. Hook"         => "Sylvias Mother",

            "Rod Stewart"    => "Maggie May",

            "Andrea Bocelli"  => "Romanza",

            "Kenny Rogers"  => "For the good times",

            "Bee Gees"        => "One night only",

            "Bonnie Tyler"    => "Hide your heart");

 

# we used the @ prefix because the return value

# represents a list

# we need to supply the keys for which we wanted

# to extract the values

@slice = @cds{"Dr. Hook","Kenny Rogers","Bee Gees"};

# we used the join function to print each string

# on a new line

print join("\n", @slice);

Running the code it will produce the output:

Sylvias Mother

For the good times

One night only

 

 

Find out if a hash variable contains references



An easy way to find out if a variable is a simple string or number, or a reference to an array or a hash or something else, is to use the ref function. The ref function has the syntax form:

ref EXPR

If EXPR is not specified, $_ will be used. This function returns an empty string if the EXPR/$_ is not a reference, and a string (the type of reference) otherwise. Look at the code below to see how it works:

# define some simple variables

# we can use the same name Ė colors for different things

$colors = "darkblue";

@colors = qw(blue, red, yellow, brown);

%colors = (c1 => "blue", c2 => "green", c3 => "yellow");

 

# define a hash with references

%moreColors = (1 => "white", 2 => \$colors,

                      3 => \@colors, 4 => \%colors);

 

# loop through %moreColors hash to find out the references

foreach $key (keys %moreColors)

{

  if (ref $moreColors{$key} eq "SCALAR") {

    print "$key: SCALAR\n";

  } elsif (ref $moreColors{$key} eq "ARRAY") {

    print "$key: ARRAY\n";

  } elsif (ref $moreColors{$key} eq "HASH") {

    print "$key: HASH\n";

  } elsif (ref $moreColors{$key} eq "") {

    print "$key: NO REFERENCE\n";

  }

}

And here is what you get as output if you run the code:

4: HASH

1: NO REFERENCE

3: ARRAY

2: SCALAR

Do you see the order (4 1 3 2) in which the keys were printed? Perl doesnít care about the sequential order (1 2 3 4) in which I initialized %moreColors hash! Remember, if you want to print Perl hashes in some order, you must sort the hashes yourself.

To sort a hash by key, you can use the following code lines:

# define a hash
%time = (hour => 12, min => 25, sec => 32, msec =>75);
 
# foreach loop
foreach $key (sort keys %time)
{
  print "$key: $time{$key}\n";
}

 

Sort or order a hash

 

 

To sort a hash by value, in a descending order, you can use the following code:

# define a hash
%v = (v1 => 75, v2 => 251, v3 => 3, v4 => 12);
 
# sort by value and put the keys in an array 
@keys = sort {$v{$b} <=> $v{$a}} keys %v;
 
# loop through array to print the hash pairs ordered
foreach $key (@keys)
{
  print "$key: $v{$key}\n";
}

If you will run the code, it will produce the following output:

v1: 251
v3: 75
v2: 12
v4: 3

In the example above, our hash has numerical values so we used the numerical operator "<=>" for the comparisons. If you want to sort the values lexically, you need to use the stringwise operator "cmp" instead of "<=>".

Insert or add new items into a hash



To insert a new (key, value) pair in a hash structure, you can use the syntax form:

$hash{"key"} = "value";

If hash doesnít exist, it will be created automatically by Perl. Please have a look at the following code to see some examples:

%ages = ("John", 43, "Paul", 25, "Marie", 22);

$ages{"Anne"} = 22;

$ages{"Paul"} = 24;

$ages{"Marie"} = 24 unless exists $ages{"Marie"} ;

$ages{"George"} = 51 unless exists $ages{"George"} ;

print %ages, "\n";

 

 

In the first line I initialized the %ages hash. In the second and the third lines I inserted two elements in the hash variable. Please beware that the key "Paul" already exists and its associated value was over-written with the new value (24). Please note the dollar sign in $ages{"Marie"} and remember that a single element of a hash is a scalar.

 

Loop or iterate through a hash



To loop or iterate through Perl hashes, you can use "each" function. This function iterates or loops through the (key, value) pairs of a hash, each (key, value) pair being returned as a two-element list. See the example below to find out how it works:

%phoneNumbers = ("Anne", "432566", "Paul", "231275", "Marie",

                 "299302");

while (($key, $value) = each %phoneNumbers)

{

  print "$key has the phone number $phoneNumbers{$key}\n";

}

The code shown above will extract the keys and values from the %phoneNumbers hash and it will display as output:

Anne has the phone number 432566

Paul has the phone number 231275

Marie has the phone number 299302

 

 

Print a hash



Iíll show you how to print the keys/values of Perl hashes. Iíll assign some elements to a hash structure (by using the syntax: $hash{$key}=value;), then Iíll iterate through the elements of the hash structure in order to print its keys/values pairs, as you see in the following snippet code:

# Iíll create a new hash - %notebookPrices

# by assigning some elements to it:

 

$notebookPrices{"Toshiba"}=650;

$notebookPrices{"HP"}=550;

$notebookPrices{"Acer"}=750;

 

# the next loop prints the keys/values of the hash

foreach $key (keys %notebookPrices)

{

  print "Key: $key, Value: \$$notebookPrices{$key}\n";

}

After running this code, youíll get the output:

Key: Acer, Value: $750

Key: Toshiba, Value: $650

Key: HP, Value: $550

 

 

Remove a key from a hash



If you want to remove a single hash (key, value) pair from Perl hashes, you can use the delete function, in one of the following syntax forms:

delete $hash{$key};

delete $hashRef->{$key};   # if you have a hash reference

delete $$hashRef{$key};     # if you have a hash reference

See the examples below about how to implement it:

%phoneNumbers = ("Anne", "408566", "Paul", "233375", "Marie",

                 "217302");

delete $phoneNumbers {"Paul"};

delete $phoneNumbers {"John"};

$phoneNumbersRef = \%phoneNumbers;

delete $$phoneNumbersRef{"Anne"};

 

#print the hash (keys, values)

foreach $key (keys % phoneNumbers)

{

  print "Key: $key, Value: $phoneNumbers{$key}\n";

}

The second line of this snippet code will have as effect the deletion of the "Paul" key from the %phoneNumbers hash. In the third line of the code we try to delete an inexistent key from the hash, the script will not return any error and the %phoneNumbers hash will remain unchanged. The last line of the above code shows you how to delete a key when you have a hash reference (we used $$hashRef{$key} notation to dereference a certain hash value, but you can use $hashRef->{$key}, too).

Reverse a hash



Because a hash represents a list of (key, value) pairs, we can reverse such a list and after that each pair will become (value, key). We'll do this by using the reverse function. However, beware that the hash keys are unique and if the values of the source hash are not unique, some elements will be lost. I want to say that if you reverse again your resulting hash, itís possible to obtain a shorter hash. Here is an example how you can implement it:

# define a hash

%cds = ("Dr. Hook"        => "Sylvias Mother",

            "Andrea Bocelli" => "Romanza",

            "Bonnie Tyler"   => "Hide your heart");

%cdsReversed = reverse %cds;

 

# weíll use Data::Dumper module to see

# what it is in the hash

use Data::Dumper;

print Dumper(%cdsReversed);

 

 

 

 

 

 

 

 

 

 

 

 

 

Copyright © 2009 Kunal Saxena Inc. All rights reserved