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

Hi Monks,

I'm sure Perl can do this, yet searching the PODs and PerlMonks Q&A comes tantilisingly close, but not close enough. I just cant find a simple explanation/example for this.

I want to store a list of things into one element of a hash, and another list in another hash etc..

First off lets just try putting one list into one hash element:

my @test = ( qw / bing bong bang / ); print '['.$test[2].'] ['.$test[1].'] ['.$test[0]."]\n"; $bits{'one'}= @test; my @new = $bits{'one'}; print '['.$new[2].'] ['.$new[1].'] ['.$new[0]."]\n"; OUTPUT: [bang] [bong] [bing] [] [] [3]
Any help or explanation would be great!

Thanks,

___ /\__\ "What is the world coming to?" \/__/ www.wolispace.com

Replies are listed 'Best First'.
Re: A hash of lists
by pg (Canon) on Nov 06, 2003 at 03:52 UTC

    Basically, when you save an array or hash as elements of a hash, you have to store the array ref or hash ref.

    See the code and comments:

    use strict; #for better practice use warnings;#same as above my @test = ( qw / bing bong bang / ); print '['.$test[2].'] ['.$test[1].'] ['.$test[0]."]\n"; my %bits;#explicitly declare your variables $bits{'one'}= \@test;#assign the array ref, not the flattened array it +self. my @new = @{$bits{'one'}};#now deref it, so you get the flattened arr +ay back. print '['.$new[2].'] ['.$new[1].'] ['.$new[0]."]\n";

    A even better way, is to use the array ref directly, instead of falttening it and copying the entire array. When the array is big, that gives you bad performance.

    use strict; use warnings; my @test = ( qw / bing bong bang / ); print '['.$test[2].'] ['.$test[1].'] ['.$test[0]."]\n"; my %bits; $bits{'one'}= \@test; my $new = $bits{'one'}; #new holds the array ref, not a copy of the e +ntire array print '['.$new->[2].'] ['.$new->[1].'] ['.$new->[0]."]\n";#to get elem +ents from array ref, use -> operator
Re: A hash of lists
by Roger (Parson) on Nov 06, 2003 at 03:53 UTC
    You are almost there...
    my @test = qw / bing bong bang /; print '['.$test[2].'] ['.$test[1].'] ['.$test[0]."]\n"; $bits{'one'}= \@test; # hash entry from a reference to array my @new = @{$bits{'one'}}; # get back the array from the hash print '['.$new[2].'] ['.$new[1].'] ['.$new[0]."]\n";
    A suggestion: use Data::Dumper to save you the trouble of all those typing. :)
    use Data::Dumper; @test = qw / bing bong bang /; print Dumper(\@test); $bits{'one'}= \@test; @new = @{$bits{'one'}}; print Dumper(\@new);
Re: A hash of lists
by jweed (Chaplain) on Nov 06, 2003 at 03:58 UTC
    When you say
    $bits{'one'}=@test;
    you are really giving @test scalar context. That's why $new[0] the second time returned 3 - that's the number of elements in @test. Basically, you can't just lay these data structures on top of each other.
    Try using a reference and dereferencing later:
    my @test = ( qw / bing bong bang / ); print '['.$test[2].'] ['.$test[1].'] ['.$test[0]."]\n"; $bits{'one'}= \@test; my @new = @{$bits{'one'}}; print '['.$new[2].'] ['.$new[1].'] ['.$new[0]."]\n"; OUTPUT: [bang] [bong] [bing] [bang] [bong] [bing]
    \@test is a reference to test, and  @{$bits{'one'}} accesses the reference ($bits{'one'}) and the @{} dereferences it. Have you tried perlreftut?


    UPDATE:
    Coruscate reminded me of one of my favorite methods of array reference that I forgot to mention - [@test]. Trust me, all the cool kids are doing it. I hear it's all the rage in Japan. Even though it isn't exactly the same as \@test, for your purposes it works the same.
    UPDATE 2:
    sauoq has a good point. Chatterbox discussion showed that in fact @{$bits{'one'}} = @test is much faster than [@test] and /@test anyway. Check out my pad for benchmarking details.
      Even though it isn't exactly the same as \@test, for your purposes it works the same.

      It's doubtful that his real purposes are anything like the example he showed, so the differences between [ @test ] and \@test may actually be quite significant.

      The first, [ @test ] actually creates a new array, a copy of @test, and returns a reference to it. The second, \@test returns a reference to @test itself.

      If @test is big, making copies of it could hurt performance.

      Also, because the data is copied, changing an element in the array referred to by [ @test ] won't have any affect on the contents of @test itself. Sometimes that's just what you want. Sometimes it isn't.

      -sauoq
      "My two cents aren't worth a dime.";
      
        Ah.. now this is interesting..

        In this instance I plan to read lines from a file and split them by their delimiter and store them as lists in a hash.

        So @test in my example is infact one line read from a file, then @test becomes another line etc..

        So what happens to the data if its references all the way down?

        I suspect I should be using the @test method in this case.

        ___ /\__\ "What is the world coming to?" \/__/ www.wolispace.com
Re: A hash of lists
by Coruscate (Sexton) on Nov 06, 2003 at 05:08 UTC

    And just because TI(always)MTOWTDI, just another twist on ways you can do it:

    $bits->{'one'} = \@test; # use a reference @{$bits->{'one'}} = @test; # copy into $bits $bits{'one'} = [@test]; # copy into anon. list $bits{'one'} = \@{[@test]}; # um yeah, having fun $bits{'one'} = [@{[@test]}]; # you wouldn't REALLY do this @{$bits{'one'}} = @{[@{[@test]}]}; # ok, that's ridiculous

(shockme) Re: A hash of lists
by shockme (Chaplain) on Nov 06, 2003 at 04:04 UTC
    Also, check out tye's References quick reference and Data::Dumper. Data::Dumper is great for determining underlying data structures and how to reference them.

    If things get any worse, I'll have to ask you to stop helping me.

Re: A hash of lists
by tcf22 (Priest) on Nov 06, 2003 at 03:52 UTC
    Try using a hash reference
    my @test = ( qw / bing bong bang / ); print '['.$test[2].'] ['.$test[1].'] ['.$test[0]."]\n"; $bits{'one'}= \@test; my @new = @{$bits{'one'}}; print '['.$new[2].'] ['.$new[1].'] ['.$new[0]."]\n"; __OUTPUT__ [bang] [bong] [bing] [bang] [bong] [bing]

    - Tom

Re: A hash of lists
by Anonymous Monk on Nov 06, 2003 at 03:54 UTC

    Please use perldoc to view the following documents on your local machine:

    perldoc perlreftut perldoc perlref perldoc perllol perldoc perldsc
Re: A hash of lists
by Roy Johnson (Monsignor) on Nov 06, 2003 at 19:10 UTC