Beefy Boxes and Bandwidth Generously Provided by pair Networks
There's more than one way to do things
 
PerlMonks  

Dereferencing a Hash of Arrays

by toro (Beadle)
on Jun 14, 2011 at 06:47 UTC ( [id://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?

Replies are listed 'Best First'.
Re: Dereferencing a Hash of Arrays
by philipbailey (Curate) 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 (Abbot) 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 (Curate) 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
Domain Nodelet?
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?Last hourOther CB clients
Other Users?
Others meditating upon the Monastery: (4)
As of 2024-04-19 21:39 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found