Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I recursively walk a nested hash data structure?

I am stuck with what looks like a simple conceptual issue to me. After diligently looking for similar issues on the Web and Stack Overflow I could not find something similar, so I thought I could ask you.

I am building a hash of hash data structure which is deeply nested. The depth can be 10-20 a times. For the sake of this issue I am listing only till depth one.

I am unable to recursively walk through the sample hash below in Perl. I also have included my code.

It gives me the following error:

Can't use string ("1") as a HASH ref while "strict refs" in use at

Just so it is clear: my hash is bound to have certain keys with value 1. I cannot avoid them.

$VAR1 = {
    'Eukaryota' => {
        'Rhodophyta'         => {'count' => 5},
        'Alveolata'          => {'count' => 16},
        'stramenopiles'      => {'count' => 57},
        'count'              => 155,
        'Glaucocystophyceae' => {'count' => 1},
        'Cryptophyta'        => {'count' => 18},
        'Malawimonadidae'    => {'count' => 1},
        'Viridiplantae'      => {'count' => 57},
    },
    'Bacteria' => {
        'Cyanobacteria'       => {'count' => 1},
        'Actinobacteria'      => {'count' => 4},
        'count'               => 33,
        'Proteobacteria'      => {'count' => 25},
        'Deinococcus-Thermus' => {'count' => 2},
        'Firmicutes'          => {'count' => 1},
    },
};

Code to recursively walk this hash:

sub analyse_contig_tree_recursively {
    my $TAXA_TREE   = shift @_;
    my $contig_hash = shift @_;
    foreach (keys %{$TAXA_TREE}) {
        print "$_ \n";
        analyse_contig_tree_recursively($TAXA_LEVEL->{$_}, $contig_hash);
    }
}
like image 715
Abhi Avatar asked Jun 03 '11 17:06

Abhi


1 Answers

I'm not sure what you're calling analyse_contig_tree_recursively on (you're not using that $contig_hash parameter anywhere, and you haven't defined $TAXA_LEVEL: did you mean $TAXA_TREE?), but there's obviously a mismatch between your data structure layout and your recursive traversal pattern. Your traversal function assumes that all the entries are hashes, and treats empty hashes as the termination case: if keys %{$TAXA_TREE} is empty, there is no recursive call. Given your data, you need to test whether a value is a hash or not, and not recurse if you find it's not a hash.

sub analyse_contig_tree_recursively {
    my $TAXA_TREE           =   shift @_;
    foreach ( keys %{$TAXA_TREE} ){
        print "$_ \n";
        if (ref $TAXA_TREE->{$_} eq 'HASH') {
            analyse_contig_tree_recursively($TAXA_TREE->{$_});
        }
    }
}
like image 82
Gilles 'SO- stop being evil' Avatar answered Nov 26 '22 21:11

Gilles 'SO- stop being evil'