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

Hi,

I would like to initialize %hash with two keys: $hash{"COUNTS"} will point to an array of size $length all initialized with 0's. $hash{"LISTS"} will point to an array of size $length, where each element is an empty list (so I can push into it).

I know how to achieve that using lopping, creating temporary structures and referencing to them, but I'm quite sure there's a more elegant solution. for example, I think that $hash{"COUNTS"} can be initialized using:

$hash{"COUNTS"}=[(0) x $length] OR $hash{"COUNTS"}=[0 x $length]

I'm not sure if the braces around the zero have any effect. Do they mean a singleton with zero in it? If I want a simple scalar, should I omit them? And how should i initialize $hash{"LISTS"}? Maybe something like

$hash{"LISTS"}=[() x $length]

thanks!

Replies are listed 'Best First'.
Re: Newbies question: initializing data structure
by moritz (Cardinal) on Jun 02, 2010 at 08:11 UTC
    I'm not sure if the braces around the zero have any effect.

    Then find it out:

    use Data::Dumper; # your initialization code here print Dumper \%hash;

    About your other questions:

    $hash{"LISTS"}=[() x $length]

    This doesn't do what you want, since you want really references to empty arrays, not empty lists (which get flattened out).

    # WRONG $hash{"LISTS"}=[([]) x $length]

    won't work either, because it returns many references to the same array.

    A working solution is

    $hash{LISTS} = [ map [], 1..$length ];

    Though often this is not needed at all, thanks to autovivification. This works without error:

    my %hash; # automatically creates $hash{LISTS} as an array ref, # and $hash{LISTS}[3] as an array ref: push @{$hash{LISTS}[3]}, 'new item'; # also works for direct assignment: $hash{LISTS}[4][0] = 'other new item';
    Perl 6 - links to (nearly) everything that is Perl 6.
Re: Newbies question: initializing data structure
by almut (Canon) on Jun 02, 2010 at 08:12 UTC
    $hash{"COUNTS"} = [ (1) x $length ];

    The parentheses around 1 are needed here (they specify a list). Otherwise you'd get one string "1111111111", because in scalar context the x operator multiplies/concatenates a string.

    For your second case:

    $hash{"LISTS"} = [ map [], 1..$length ];

    ( () x $length wouldn't work here)

      Thanks! Let me compllicate that just a bit. suppose I would like to construct an array of length $arr_len of such hashes. What do I do?

        You could apply the same technique:

        my @array = map { LISTS => [ map [], 1..$length ] }, 1..$arr_len;


        P.S.: when you play with this, you'll sooner or later encounter curious things like this:

        my @array = map { 'foo' => $_ }, 1..3; # ok my @array = map { $_ => 'foo' }, 1..3; # not ok: 'syntax error at . +.., near "},"'

        This is because Perl has to guess whether the {...} is an anonymous hash or a block (remember, map supports both map EXPR, LIST and map BLOCK LIST syntax).  In order to be sure what is meant, Perl would have to look ahead up until after the corresponding closing curly to see if there's a comma or not, which would disambiguate the interpretation. Perl doesn't do this, because the closing curly could potentially be many lines later... Rather, it expects you to help disambiguate early, like with a unary plus in this case:

        my @array = map +{ $_ => 'foo' }, 1..3; # ok

        (see map for details)

      Thanks! Let me complicate that just a bit. suppose I would like to construct an array of length $arr_len of such hashes. What do I do?

        specifically, I noticed my @arr = {map { }, 1 .. $arr_len} seems to work, rather than my first guess, which was my @arr = [map { }, 1 .. $arr_len].

        But shouldn't we return a array to assign into @arr? hence use square brackets?

Re: Newbies question: initializing data structure
by shawnhcorey (Friar) on Jun 02, 2010 at 12:44 UTC

    What happens if you just start using the hash without initializing it? Most of the time, Perl does the right thing without complaint. If you add to a element that does not exists, Perl pretends it's zero and adds the number. If you push on a non-existent array, Perl creates it and pushes the value.

    But if you insist on initializing the hash, use a simple loop:

    #!/usr/bin/perl use strict; use warnings; my %hash = (); my $length = 10; for my $index ( 0 .. $length-1 ){ $hash{COUNTS}[$index] = 0; $hash{LISTS}[$index] = []; } print '%hash ', Dumper \%hash;
Re: Newbies question: initializing data structure
by BioLion (Curate) on Jun 02, 2010 at 16:46 UTC

    Seeing as OP's question has already been well answered, I just wanted to add a few good resources for further reading - perldsc, perlref and Data::Dumper (for inspecting datastructures). Hope this helps!

    Just a something something...
      Thanks everybody, it's been a pleasure, as always, to get your wise words.
Re: Newbies question: initializing data structure
by shivag (Novice) on Oct 27, 2010 at 16:40 UTC
    I had a huge problem with hash variables. The easiest solution I found was to undef($var{LISTS}) and have your routine build it from scratch every time.