Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

for my $directory (@directories) { # read all subdirs $hierarchy{$directory} = (); opendir DIR, $directory; for my $filename (readdir DIR) { # remove filename extension ($filename) = split('.', $filename); print $filename; push($hierarchy{$directory}, $filename); } closedir DIR; }

Produces the following error:

Type of arg 1 to push must be array (not hash element) at admin.pl line 230, near "$filename)"

How do I force each hash element to contain an array?

Replies are listed 'Best First'.
Re: Forcing Array Context
by broquaint (Abbot) on Jun 25, 2003 at 09:29 UTC
    In this case you need to dereference the first parameter of push e.g
    my %hash = ( foo => [ ] ); push @{ $hash{foo} }, "a string"; print $hash{foo}->[0]; __output__ a string
    This is because push expects an array as the first parameter, and because hash values can only hold scalar values you have to dereference the value for push. For more info on dereferencing see. tye's References quick reference and perlreftut.
    HTH

    _________
    broquaint

      Thanks. One follow-up question: would the %hash = ( foo => []); blank the rest of %hash if it were used in a loop like I posted?

        Yep, %hash would be blanked. That particular line was just verbose initialization as push will auto-vivify the key and the array reference (i.e it will create both automatically). So assuming you're happy to initialize each key then a simple $hash{foo} = [] will suffice.
        HTH

        _________
        broquaint

Re: Forcing Array Context
by ViceRaid (Chaplain) on Jun 25, 2003 at 09:32 UTC

    Hi

    The value of a hash key can only be a reference to an array, not an array itself. So: instead of:

    # not $hierarchy{$directory} = (); # but $hierarchy{$directory} = []; # later, not push($hierarchy{$directory}, $filename); # but push(@{ $hierarchy{$directory} }, $filename);

    perldoc perlref is your friend

    HTH
    ViceRaid

      Thanks for the reply.

      If I were to then return \%hierarchy to a scalar variable how would I go about printing out the results?

        I suggest you take a look at the tutorials broquaint suggested; this should all become less mysterious. As for your question, the same principle applies as above: if you've got a reference in $ref put the sigil for the relevant type before it to dereference it. You'll get something like %$ref, @$ref, $$ref.

        my $hierarchy = get_hierarchy(@dirs); while ( my ( $directory, $contents ) = each %$hierarchy ) { ... # do your thing here }

        ViceRaid

        I think I've got it:

        for (keys %{ $scalar }) { print "$_\n" for @{$_}; }

        Does that look right?