Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to iterate through Hash (of Hashes) in Perl?

I have Hash where values of keys are other Hashes.

Example: {'key' => {'key2' => {'key3' => 'value'}}}

How can I iterate through this structure?

like image 437
Jay Gridley Avatar asked Mar 02 '10 12:03

Jay Gridley


People also ask

How do I iterate over a hash in Perl?

Loop over Perl hash values Perl allows to Loop over its Hash values. It means the hash is iterative type and one can iterate over its keys and values using 'for' loop and 'while' loop. In Perl, hash data structure is provided by the keys() function similar to the one present in Python programming language.

How do I read a hash in Perl?

Perl for Beginners: Learn A to Z of Perl Scripting Hands-on A hash is a set of key/value pairs. Hash variables are preceded by a percent (%) sign. To refer to a single element of a hash, you will use the hash variable name preceded by a "$" sign and followed by the "key" associated with the value in curly brackets..

How get key from hash value in Perl?

Extracting Keys and Values from a Hash variable The list of all the keys from a hash is provided by the keys function, in the syntax: keys %hashname . The list of all the values from a hash is provided by the values function, in the syntax: values %hashname . Both the keys and values function return an array.

How do I create an array of hashes in Perl?

To add another hash to an array, we first initialize the array with our data. Then, we use push to push the new hash to the array. The new hash should have all of its data. As shown below, you can see the difference between the two arrays before and after pushing a new hash.


1 Answers

This answer builds on the idea behind Dave Hinton's -- namely, to write a general purpose subroutine to walk a hash structure. Such a hash walker takes a code reference and simply calls that code for each leaf node in the hash.

With such an approach, the same hash walker can be used to do many things, depending on which callback we give it. For even more flexibility, you would need to pass two callbacks -- one to invoke when the value is a hash reference and the other to invoke when it is an ordinary scalar value. Strategies like this are explored in greater depth in Marc Jason Dominus' excellent book, Higher Order Perl.

use strict;
use warnings;

sub hash_walk {
    my ($hash, $key_list, $callback) = @_;
    while (my ($k, $v) = each %$hash) {
        # Keep track of the hierarchy of keys, in case
        # our callback needs it.
        push @$key_list, $k;

        if (ref($v) eq 'HASH') {
            # Recurse.
            hash_walk($v, $key_list, $callback);
        }
        else {
            # Otherwise, invoke our callback, passing it
            # the current key and value, along with the
            # full parentage of that key.
            $callback->($k, $v, $key_list);
        }

        pop @$key_list;
    }
}

my %data = (
    a => {
        ab => 1,
        ac => 2,
        ad => {
            ada => 3,
            adb => 4,
            adc => {
                adca => 5,
                adcb => 6,
            },
        },
    },
    b => 7,
    c => {
        ca => 8,
        cb => {
            cba => 9,
            cbb => 10,
        },
    },
);

sub print_keys_and_value {
    my ($k, $v, $key_list) = @_;
    printf "k = %-8s  v = %-4s  key_list = [%s]\n", $k, $v, "@$key_list";
}

hash_walk(\%data, [], \&print_keys_and_value);
like image 128
FMc Avatar answered Sep 19 '22 18:09

FMc