Beefy Boxes and Bandwidth Generously Provided by pair Networks
Syntactic Confectionery Delight
 
PerlMonks  

Dereferencing a Hash of Arrays

by toro (Beadle)
on Jun 14, 2011 at 06:47 UTC ( #909529=perlquestion: print w/ replies, xml ) Need Help??
toro has asked for the wisdom of the Perl Monks concerning the following question:

I thought the following would print  1 2 3 4 \n 9 8 7 6 .

my @atags = qw( 1 2 3 4 ); my @btags = qw( 9 8 7 6 ); my %alphabet = \( 'a' => @atags, 'b' => @btags, ); say for @{values %alphabet};

Instead I get:

Can't use string ("2") as an ARRAY ref while "strict refs" in use at ./concat.pl line 9 (#1) (F) Only hard references are allowed by "strict refs". Symbolic references are disallowed. See perlref. Uncaught exception from user code: Can't use string ("2") as an ARRAY ref while "strict refs" in use +at ./concat.pl line 9. at ./concat.pl line 9

What am I doing wrong?

Comment on Dereferencing a Hash of Arrays
Select or Download Code
Replies are listed 'Best First'.
Re: Dereferencing a Hash of Arrays
by philipbailey (Chaplain) on Jun 14, 2011 at 07:19 UTC

    Your problem is that the values in hashes can only be scalars in Perl. However references are scalars, so you can use references to arrays:

    my %alphabet = ( a => \@atags, b => \@btags, ); say for values %alphabet;

      Hi Philipbailey, I tried that earlier but man perlref told me I could abbreviate that as my alphabet = \(.... Are they not the same?

Re: Dereferencing a Hash of Arrays
by jwkrahn (Monsignor) on Jun 14, 2011 at 07:29 UTC

    You have two problems:

    my %alphabet = \( 'a' => @atags, 'b' => @btags, );

    You are using a list reference which produces a list of references, so your hash is the same as:

    my %alphabet = ( \'a' => \@atags, \'b' => \@btags, );


    say for @{values %alphabet};

    The construct @{} dereferences an array reference but values %alphabet does not return an array reference, it returns a list.

      input:

      my @atags = qw( 1 2 3 4 ); my @btags = qw( 9 8 7 6 ); my %alphabet = ( 'a' => \@atags, 'b' => \@btags, ); say for values %alphabet;

      output:

      ARRAY(0x8376dd8) ARRAY(0x837f298)

      UPDATE: I did say for values %alphabet in response to an earlier version of Re^1 without the @{...}. My original code was my %alphabet = ('a', \@atags, 'b', \@btags); say for @{values %alphabet}; which prints an error similar to the OP.

        The "values" are array references so you have to dereference them using @{ ... } to get the array elements. You can also get there using keys and dereferencing the looked up value in the hash.

        knoppix@Microknoppix:~$ perl -MData::Dumper -Mstrict -wE ' > my @aTags = ( 1 .. 4 ); > my @bTags = reverse 6 .. 9; > my %alpha = ( a => \ @aTags, b => \ @bTags ); > print Data::Dumper->Dumpxs( [ \ %alpha ], [ qw{ *alpha } ] ); > say q{-} x 20; > say qq{@{ $_ }} for values %alpha; > say q{-} x 20; > say qq{@{ $alpha{ $_ } }} for keys %alpha; > say q{-} x 20; > foreach my $arrayRef ( values %alpha ) > { > say for @{ $arrayRef }; > say q{-} x 20; > } > foreach my $key ( keys %alpha ) > { > say for @{ $alpha{ $key } }; > say q{-} x 20; > }' %alpha = ( 'a' => [ 1, 2, 3, 4 ], 'b' => [ 9, 8, 7, 6 ] ); -------------------- 1 2 3 4 9 8 7 6 -------------------- 1 2 3 4 9 8 7 6 -------------------- 1 2 3 4 -------------------- 9 8 7 6 -------------------- 1 2 3 4 -------------------- 9 8 7 6 -------------------- knoppix@Microknoppix:~$

        I hope this is helpful.

        Update: Expanded the example code to show how to print one element per line as the OP's code seemed to want.

        Cheers,

        JohnGG

Re: Dereferencing a Hash of Arrays
by Eliya (Vicar) on Jun 14, 2011 at 07:15 UTC

    values returns two individual array references, which you can't dereference in one go. You have to iterate over them:

    for my $aref (values %alphabet) { say for @$aref; }

    Also, you probably meant to take references of the arrays only, not of every element used to initialize the hash.   \( ... ) takes references of every element of the (unflattened!) list, so the resulting data structure is

    ... use Data::Dumper; print Dumper \%alphabet;
    $VAR1 = { 'SCALAR(0x783790)' => [ '1', '2', '3', '4' ], 'SCALAR(0x783e50)' => [ '9', '8', '7', '6' ] };

    which is probably not what you intended. (The scalar refs are stringified here, because hash keys are always strings in Perl.)

      Hmm ... so why does this work?

      my @idontgetit = values %alphabet; say for @idontgetit->[0]->[0];

      (It doesn't "work" in the sense of printing out what's desired but it does print out part of what's desired.)

        @idontgetit holds the two array refs. @idontgetit->[0] indexes the first one of it, and the second ->[0] indexes the first element of the (inner) array.

        BTW, @idontgetit->[0]->[0] should better be written as $idontgetit[0]->[0]   (turn on warnings, and Perl will tell you why).

Re: Dereferencing a Hash of Arrays
by chromatic (Archbishop) on Jun 14, 2011 at 07:23 UTC

    The reference operator here is a mistake, but it saves you a worse error:

    my %alphabet = \(

    You need to take references to both arrays in the list used to initialize the hash without taking references to the strings intended as keys.

      input:

      my @atags = qw( 1 2 3 4 ); my @btags = qw( 9 8 7 6 ); my %alphabet = ( 'a' => \@atags, 'b' => \@btags, ); say for @{values %alphabet};

      output:

      Can't use string ("2") as an ARRAY ref while "strict refs" in use at ./concat.pl line 9 (#1) (F) Only hard references are allowed by "strict refs". Symbolic references are disallowed. See perlref. Uncaught exception from user code: Can't use string ("2") as an ARRAY ref while "strict refs" in use +at ./concat.pl line 9. at ./concat.pl line 9

        From perldoc values:

        (In a scalar context, returns the number of values.)

        You'll see the error to which I alluded if you print the keys of the hash.

Re: Dereferencing a Hash of Arrays
by stefbv (Deacon) on Jun 14, 2011 at 07:00 UTC

    Values returns an array.

    The values function returns a list.

    say for values %alphabet;

    Updated as jwkrahn suggested, thanks.

        Yes, I should 'use strict' when explaining about Perl functions :)
      Well, it returns two arrays. How do I get the program to spit out [1, 2, 3, 4]; [9, 8, 7, 6] ?
        Only one :), with 2 array refs. (AoA)
        say "@$_" for values %alphabet;

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://909529]
Approved by philipbailey
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others drinking their drinks and smoking their pipes about the Monastery: (7)
As of 2015-07-08 01:54 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    The top three priorities of my open tasks are (in descending order of likelihood to be worked on) ...









    Results (93 votes), past polls