error when accessing hash of arrays

Discussion in 'Perl Misc' started by Harald, Mar 14, 2006.

  1. Harald

    Harald Guest

    HI!

    I am a perl newbie and have a problem which can be reduced to the following:

    I have a hash-reference of a hash, which values are references to
    arrays. Now I want to know the length of the first value. I try it with:

    use strict;

    my $hash = {"A"=>[1,2,3,4], "B"=>[5,6,7,8]};
    my $length = $#{values(%{$hash})[0]};
    print $length;

    But if I run it, perl says:
    ##############
    Global symbol "$length" requires explicit package name at t.pl line 5.
    Execution of t.pl aborted due to compilation errors.
    ##############
    what is absolutely strange to me.
    If I comment out line 5 (which is "print ..."), I receive the error:
    ###############
    syntax error at t.pl line 4, near ")["
    Execution of t.pl aborted due to compilation errors.
    ###############
    Which is nearly as strange to me than the first error-message.

    As far as I understand, $hash is dereferenced by %{$hash}.
    Then I get a list of all its values by values( %{$hash} ).
    Then I get its first value by values( %{$hash} )[0].
    Then I dereference it and get its size minus 1 by $#{values(%{$hash})[0]}

    Could anyone tell me where my mistake is?

    Regards and thanks in advance,
    Harald
     
    Harald, Mar 14, 2006
    #1
    1. Advertising

  2. Harald <> wrote in news:dv6hmr$5m1$02$-online.com:

    > I have a hash-reference of a hash, which values are references to
    > arrays. Now I want to know the length of the first value. I try it
    > with:
    >
    > use strict;
    >
    > my $hash = {"A"=>[1,2,3,4], "B"=>[5,6,7,8]};
    > my $length = $#{values(%{$hash})[0]};
    > print $length;


    If that worked, it would have given you the index of the last element,
    not the length of the array.

    Second, there is no "first" element of a hash. By its very nature, a
    hash table is unordered (unless you are using Tie::IxHash).

    Let's see:

    $hash->{A}

    is a reference to an array.

    @[ $hash->{A} ]

    dereferences it.

    my $length = @[ $hash->{A} ];

    Assigns the length of the array to $length.

    Alternatively:

    #!/usr/bin/perl

    use strict;
    use warnings;

    my $hash = { A =>[1,2,3,4], B => [5,6,7,8] };

    for my $v ( values %{ $hash } ) {
    print scalar @$v, "\n";
    }
    __END__

    --
    A. Sinan Unur <>
    (remove .invalid and reverse each component for email address)

    comp.lang.perl.misc guidelines on the WWW:
    http://mail.augustmail.com/~tadmc/clpmisc/clpmisc_guidelines.html
     
    A. Sinan Unur, Mar 14, 2006
    #2
    1. Advertising

  3. Harald

    Paul Lalli Guest

    Harald wrote:
    > I am a perl newbie and have a problem which can be reduced to the following:
    >
    > I have a hash-reference of a hash, which values are references to
    > arrays. Now I want to know the length of the first value. I try it with:


    Careful with your terminology. "length" generally refers to the number
    of characters in a string. (See: perldoc -f length). You're looking
    for the *size* of an array.

    > use strict;
    >
    > my $hash = {"A"=>[1,2,3,4], "B"=>[5,6,7,8]};
    > my $length = $#{values(%{$hash})[0]};
    > print $length;
    >
    > But if I run it, perl says:
    > ##############
    > Global symbol "$length" requires explicit package name at t.pl line 5.
    > Execution of t.pl aborted due to compilation errors.
    > ##############
    > what is absolutely strange to me.


    That's perl-speak for "I couldn't compile this line, so $length was
    never declared". At least, that's how I interpret it.

    > If I comment out line 5 (which is "print ..."), I receive the error:
    > ###############
    > syntax error at t.pl line 4, near ")["
    > Execution of t.pl aborted due to compilation errors.
    > ###############
    > Which is nearly as strange to me than the first error-message.


    And yet, it's completely accurate.

    > As far as I understand, $hash is dereferenced by %{$hash}.


    yes.

    > Then I get a list of all its values by values( %{$hash} ).


    yes.

    > Then I get its first value by values( %{$hash} )[0].


    no!

    the [0] is attempting to be applied to the (%{$hash}), not to the list
    returned by values(). You're getting bitten by precedence.

    (values ( %{$hash} ) )[0]

    > Then I dereference it and get its size minus 1 by $#{values(%{$hash})[0]}


    $#{ (values (%{$hash}) )[0] }

    > Could anyone tell me where my mistake is?


    Your actual mistake I've already addressed. Your first mistake,
    however, is trying to do this all in one line, IMO. :)

    my @values = values %{$hash};
    my $size_of_first = @{ $values[0] };

    Does it take longer to write? Yes. But it's also a lot easier to
    understand.

    Paul Lalli
     
    Paul Lalli, Mar 14, 2006
    #3
  4. Harald

    Guest

    Harald <> wrote:
    > HI!
    >
    > I am a perl newbie and have a problem which can be reduced to the
    > following:
    >
    > I have a hash-reference of a hash, which values are references to
    > arrays. Now I want to know the length of the first value. I try it with:


    Generally, hashes have no "first" value. Do you want the length of (the
    array referenced by) an arbitrary entry?


    >
    > use strict;
    >
    > my $hash = {"A"=>[1,2,3,4], "B"=>[5,6,7,8]};
    > my $length = $#{values(%{$hash})[0]};
    > print $length;


    Thank you for using strict, and for posting complete, runnable (well,
    runnable other than the very syntax error which you were asking about)
    code.

    [0] is used to index into either an array or a list. But to index into
    a list, the list must be paranthesized. In this case, your intended list
    is not parenthesized. Move the '(' from just after to just before the
    "values".

    my $length = $#{(values %{$hash})[0]};

    Now the list returned by values is a paranthesized and hence indexable
    list, and it will work. (But it isn't the length, it is the index of the
    last element, i.e. the length minus one.)


    >
    > But if I run it, perl says:
    > ##############
    > Global symbol "$length" requires explicit package name at t.pl line 5.
    > Execution of t.pl aborted due to compilation errors.
    > ##############


    In my perl, I get the below syntax error first, then the above "requires
    explicit package" on the next line. Are you sure that isn't the case for
    you as well, and perhaps you are missing the first error statment?

    Anyway, perl doesn't just stop at the first syntax error it sees. It tries
    to go on to critique the rest of your code as well. But to do so, it has
    to somehow recover from the syntax error. That recovery is rarely perfect,
    and here one result of it is that it fails to record the "my"ing of
    $length.

    Generally, any errors or warnings reported after the occurence of a syntax
    error are dubious.

    Xho

    --
    -------------------- http://NewsReader.Com/ --------------------
    Usenet Newsgroup Service $9.95/Month 30GB
     
    , Mar 14, 2006
    #4
  5. Harald

    Harald Guest

    Hello,

    thanks for your reply.
    In my problem all the arrays that are hashed are of the same length so I
    am just interested in one arrays size. No matter which. So I will stick
    with the solution of the other posters.

    Thanks a lot for your reply and your comments. Perl becomes more and
    more clearer.

    but this does not work with my perl:

    >
    > my $length = @[ $hash->{A} ];
    >


    It works only with
    my $length = @{ $hash->{A} };

    Regards,
    Harald
     
    Harald, Mar 14, 2006
    #5
  6. Harald

    Harald Guest

    Hello.

    Thanks a lot. I had tried it with brackets to inforce the right operator
    precedence but it lead to errors because I tried to do it all in one line.

    But you are right. Breaking it up into two lines is much more readable!

    Regards,
    Harald
     
    Harald, Mar 14, 2006
    #6
  7. Harald

    Harald Guest

    Hello.

    Thanks a lot.
    As far as I imagine I had tried it with different ways of ('s and )'s
    but it did not work :-(

    And no, the error message was produces just as I have printed it in my
    first mail.

    Regards,
    Harald
     
    Harald, Mar 14, 2006
    #7
  8. Harald <> wrote in news:dv6p0h$ggb$00$-online.com:

    > but this does not work with my perl:
    >
    >>
    >> my $length = @[ $hash->{A} ];
    >>

    >
    > It works only with
    > my $length = @{ $hash->{A} };


    Of course, I was typing too fast for my own good. Thanks for catching
    that.

    Sinan
    --
    A. Sinan Unur <>
    (remove .invalid and reverse each component for email address)

    comp.lang.perl.misc guidelines on the WWW:
    http://mail.augustmail.com/~tadmc/clpmisc/clpmisc_guidelines.html
     
    A. Sinan Unur, Mar 14, 2006
    #8
  9. Harald <> wrote:

    > the error message was produces just as I have printed it in my
    > first mail.



    This is not email.

    This is a Usenet newsgroup.

    The difference matters.


    --
    Tad McClellan SGML consulting
    Perl programming
    Fort Worth, Texas
     
    Tad McClellan, Mar 14, 2006
    #9
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Philipp
    Replies:
    21
    Views:
    1,157
    Philipp
    Jan 20, 2009
  2. rp
    Replies:
    1
    Views:
    556
    red floyd
    Nov 10, 2011
  3. Adam Akhtar
    Replies:
    5
    Views:
    660
    Adam Akhtar
    Mar 25, 2008
  4. Älphä Blüë

    Hash of Hash of Arrays Question

    Älphä Blüë, Jul 18, 2009, in forum: Ruby
    Replies:
    5
    Views:
    676
    Älphä Blüë
    Jul 18, 2009
  5. Lynn

    Accessing Hash of hash of arrays

    Lynn, Feb 14, 2005, in forum: Perl Misc
    Replies:
    9
    Views:
    558
    Alan J. Flavell
    Feb 16, 2005
Loading...

Share This Page