Search code examples
arraysperlhashdereference

De-reference x number of times for x number of data structures


I've come across an obstacle in one of my perl scripts that I've managed to solve, but I don't really understand why it works the way it works. I've been scouring the internet but I haven't found a proper explanation.

I have a subroutine that returns a reference to a hash of arrays. The hash keys are simple strings, and the values are references to arrays.

I print out the elements of the array associated with each key, like this

for my $job_name (keys %$build_numbers) {
    print "$job_name => ";
    my @array = @{@$build_numbers{$job_name}};  # line 3
    for my $item ( @array ) {
        print "$item \n";
    } 
}

While I am able to print out the keys & values, I don't really understand the syntax behind line 3.

Our data structure is as follows:

Reference to a hash whose values are references to the populated arrays.

To extract the elements of the array, we have to: - dereference the hash reference so we can access the keys - dereference the array reference associated to a key to extract elements.

Final question being:

  • When dealing with perl hashes of hashes of arrays etc; to extract the elements at the "bottom" of the respective data structure "tree" we have to dereference each level in turn to reach the original data structures, until we obtain our desired level of elements?

Hopefully somebody could help out by clarifying.


Solution

  • Line 3 is taking a slice of your hash reference, but it's a very strange way to do what you're trying to do because a) you normally wouldn't slice a single element and b) there's cleaner and more obvious syntax that would make your code easier to read.

    If your data looks something like this:

    my $data = {
        foo => [0 .. 9],
        bar => ['A' .. 'F'],
    };
    

    Then the correct version of your example would be:

    for my $key (keys(%$data)) {
        print "$key => ";
    
        for my $val (@{$data->{$key}}) {
            print "$val ";
        }
    
        print "\n";
    }
    

    Which produces:

    bar => A B C D E F
    foo => 0 1 2 3 4 5 6 7 8 9
    

    If I understand your second question, the answer is that you can access precise locations of complex data structures if you use the correct syntax. For example:

    print "$data->{bar}->[4]\n";
    

    Will print E.

    Additional recommended reading: perlref, perlreftut, and perldsc