error when accessing hash of arrays

H

Harald

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
 
A

A. Sinan Unur

Harald said:
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__
 
P

Paul Lalli

Harald said:
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
 
X

xhoster

Harald said:
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
 
H

Harald

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
 
H

Harald

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
 
H

Harald

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
 
T

Tad McClellan

Harald said:
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.
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,055
Latest member
SlimSparkKetoACVReview

Latest Threads

Top