Can't use undefined value as a HASH reference

A

alexbarham

I am working through the Mastering Algorithms with PERL and there is a
section of code I don't quite honestly understand and it is giving me a
compile error of "Can't use an undefined value as a HASH reference".
Here is the code:

#! /usr/bin/perl -w

sub intersection
{
my($i,$sizei) = (0,scalar keys%{$_[0]});
my($j,$sizej);

for($j=1;$j<@_;$j++)
{
$sizej = scalar keys %{$_[$j]};
}
($i,$sizei) = ($j,$sizej) if $sizej < $sizei;

my @intersection = keys %{splice @_,$i,1};
my $set;
while($set = shift)
{
@intersection = grep {exists $set->{$_}} @intersection;
}

my %intersection;
@intersection {@intersection} = ();

return \%intersection;

}

@Cats{qw(cat lion tiger)} = ();
@Asian{qw(tiger panda yak)} = ();
@Striped{qw(zebra tiger)} = ();

@Cats_Asian_Striped = intersection(\%Cats,\%Asian,\%Striped);

print join(" ",keys %{$Cats_Asian_Striped}),"\n";

This should output just tiger (the intersection of all three hashes).
Can someone please explain the syntax of the line:

I have two questions about the code:

1) The following line is where the error is generated:
my @intersection = keys %{splice @_,$i,1);
I understand what a splice does but if I understand correctly, @_
refers to the arguments passed into the subroutine. $i is initialized
to 0 at the beginning of the script and then gets set to the smallest
array. This should be @Striped, which is equal to 2. Thus
splice(@_,2,1) looks to me like it will remove the @Striped from @_??
How can I fix this to eliminate the error?
2) What kind of data structure is the following line:
@Cats{qw(cat lion tiger)} = ();
It start with an array symbol but the parenthese look like it is
initialized to zero elements??

Thank you for your help
 
X

xhoster

I am working through the Mastering Algorithms with PERL and there is a
section of code I don't quite honestly understand and it is giving me a
compile error of "Can't use an undefined value as a HASH reference".
Here is the code:

This code came directly from Mastering Algorithms, or is it something
you whipped up yourself?
#! /usr/bin/perl -w

sub intersection
{
my($i,$sizei) = (0,scalar keys%{$_[0]});
my($j,$sizej);

for($j=1;$j<@_;$j++)
{
$sizej = scalar keys %{$_[$j]};
}
($i,$sizei) = ($j,$sizej) if $sizej < $sizei;

It seems like this last line should be inside the loop, not after
it.

I have two questions about the code:

1) The following line is where the error is generated:
my @intersection = keys %{splice @_,$i,1);
I understand what a splice does but if I understand correctly, @_
refers to the arguments passed into the subroutine. $i is initialized
to 0 at the beginning of the script and then gets set to the smallest
array. This should be @Striped, which is equal to 2.

You think $i should be 2. Add a print or a warn statement to see if it
actually is.
2) What kind of data structure is the following line:
@Cats{qw(cat lion tiger)} = ();

It is a hash slice. See the section on slices in perldoc perldata.
It start with an array symbol but the parenthese look like it is
initialized to zero elements??


Xho
 
A

alexbarham

I am working through the Mastering Algorithms with PERL and there is a
section of code I don't quite honestly understand and it is giving me a
compile error of "Can't use an undefined value as a HASH reference".
Here is the code:

This code came directly from Mastering Algorithms, or is it something
you whipped up yourself?
#! /usr/bin/perl -w

sub intersection
{
my($i,$sizei) = (0,scalar keys%{$_[0]});
my($j,$sizej);

for($j=1;$j<@_;$j++)
{
$sizej = scalar keys %{$_[$j]};
}
($i,$sizei) = ($j,$sizej) if $sizej < $sizei;

It seems like this last line should be inside the loop, not after
it.

I have two questions about the code:

1) The following line is where the error is generated:
my @intersection = keys %{splice @_,$i,1);
I understand what a splice does but if I understand correctly, @_
refers to the arguments passed into the subroutine. $i is initialized
to 0 at the beginning of the script and then gets set to the smallest
array. This should be @Striped, which is equal to 2.

You think $i should be 2. Add a print or a warn statement to see if it
actually is.
2) What kind of data structure is the following line:
@Cats{qw(cat lion tiger)} = ();

It is a hash slice. See the section on slices in perldoc perldata.
It start with an array symbol but the parenthese look like it is
initialized to zero elements??


Xho

Actually this code is directly from Mastering Algorithms with PERL. I
changed the code to the following:

#! /usr/bin/perl -w


sub intersection
{
my($i,$sizei) = (0,scalar keys%{$_[0]});
my($j,$sizej);


for($j=1;$j<@_;$j++)
{
$sizej = scalar keys %{$_[$j]};
}
($i,$sizei) = ($j,$sizej) if $sizej < $sizei;

print $i,"\n";
my @intersection = keys %{splice @_,$i,1};
my $set;
while($set = shift)
{
@intersection = grep {exists $set->{$_}} @intersection;

}


my %intersection;
@intersection {@intersection} = ();


return \%intersection;



}


@Cats{qw(cat lion tiger)} = ();
@Asian{qw(tiger panda yak)} = ();
@Striped{qw(zebra tiger)} = ();

@Cats_Asian_Striped = intersection(\%Cats,\%Asian,\%Striped);

foreach my $cat(keys %Cats_Asian_Striped){
print $Cats_Asian_Striped{$cat},"\n";
}

print join(" ",keys %{$Cats_Asian_Striped}),"\n";

The line:

my @intersection = keys %{splice @_,$i,1};

still generates the error: "Can't use and undefined value as a HASH
reference at intersection.pl line 17". The value the print $i,"\n";
prints is 3. If I change the line to:

my @intersection = keys %{splice @_,2,1,}; or @intersection = keys
%{splice @_,1,1};

The error disappears but the for loop doesn't print anything. However,
If I add in:

print scalar @Cats_Asian_Striped;

I get a 1, which I would imagine means that there is 1 element in the
array.

Hopefully that will shed some light on the error.

Thanks
 
P

Paul Lalli

I am working through the Mastering Algorithms with PERL and there is a
section of code I don't quite honestly understand and it is giving me a
compile error of "Can't use an undefined value as a HASH reference".
Here is the code:

#! /usr/bin/perl -w

sub intersection
{
my($i,$sizei) = (0,scalar keys%{$_[0]});
my($j,$sizej);

for($j=1;$j<@_;$j++)
{
$sizej = scalar keys %{$_[$j]};
}
($i,$sizei) = ($j,$sizej) if $sizej < $sizei;

This line belongs in the loop above. That is the root cause of the
error you spotted, because...
my @intersection = keys %{splice @_,$i,1};

The way the code is written, $i is assigned to $j after the loop has
ended, making $i equal to three, which is outside the bounds of @_,
which causes the splice to return undef.
my $set;
while($set = shift)
{
@intersection = grep {exists $set->{$_}} @intersection;
}

my %intersection;
@intersection {@intersection} = ();

return \%intersection;

}

@Cats{qw(cat lion tiger)} = ();
@Asian{qw(tiger panda yak)} = ();
@Striped{qw(zebra tiger)} = ();

@Cats_Asian_Striped = intersection(\%Cats,\%Asian,\%Striped);

This line is also incorrect. intersection() returns a hash reference.
Its return value should be assigned to a scalar variable,
$Cats_Asian_Striped, not an array variable
print join(" ",keys %{$Cats_Asian_Striped}),"\n";

Without that fix, you would likely get another "can't use uninitialized
variable as HASH ref" here as well. (If the author had used strict, he
would have spotted this error immediately...)
This should output just tiger (the intersection of all three hashes).
Can someone please explain the syntax of the line:

What line?
I have two questions about the code:

1) The following line is where the error is generated:
my @intersection = keys %{splice @_,$i,1);
I understand what a splice does but if I understand correctly, @_
refers to the arguments passed into the subroutine. $i is initialized
to 0 at the beginning of the script and then gets set to the smallest
array.

No, it gets set to the *index* of the smallest hash. Or at least, it
*will*, once you fix the code by putting that assignment of $i and
$isize back into the for loop where it belongs.
This should be @Striped

%Striped. It's a hash, not an array.
, which is equal to 2. Thus
splice(@_,2,1) looks to me like it will remove the @Striped from @_??

Yes, but that's only half the point. In addition to removing elements
from the array, splice also *returns* the elements it removes.
Therefore, the %{ } syntax surrounding the splice call will dereference
the hashref that splice removes.

The hash is removed so that when the while loop iterates through @_
later (shift operates on @_ by default), it will not try to reprocess
this hash.
How can I fix this to eliminate the error?

See above.
2) What kind of data structure is the following line:
@Cats{qw(cat lion tiger)} = ();
It start with an array symbol but the parenthese look like it is
initialized to zero elements??

It is a hash slice. Much like you refer to a single element of a hash
%Cats like:
$Cats{'cat'}
you can refer to several elements of the hash as:
@Cats{'cat', 'lion', 'tiger'};

This is a bizarre way of intializing several keys of a hash all to the
value of undef. It would, in my opinion, be more clearly written:
my %Cats;
$Cats{$_} = undef for qw/cat lion tiger/;
Thank you for your help

You're welcome.

Paul Lalli
 
A

alexbarham

Paul said:
I am working through the Mastering Algorithms with PERL and there is a
section of code I don't quite honestly understand and it is giving me a
compile error of "Can't use an undefined value as a HASH reference".
Here is the code:

#! /usr/bin/perl -w

sub intersection
{
my($i,$sizei) = (0,scalar keys%{$_[0]});
my($j,$sizej);

for($j=1;$j<@_;$j++)
{
$sizej = scalar keys %{$_[$j]};
}
($i,$sizei) = ($j,$sizej) if $sizej < $sizei;

This line belongs in the loop above. That is the root cause of the
error you spotted, because...
my @intersection = keys %{splice @_,$i,1};

The way the code is written, $i is assigned to $j after the loop has
ended, making $i equal to three, which is outside the bounds of @_,
which causes the splice to return undef.
my $set;
while($set = shift)
{
@intersection = grep {exists $set->{$_}} @intersection;
}

my %intersection;
@intersection {@intersection} = ();

return \%intersection;

}

@Cats{qw(cat lion tiger)} = ();
@Asian{qw(tiger panda yak)} = ();
@Striped{qw(zebra tiger)} = ();

@Cats_Asian_Striped = intersection(\%Cats,\%Asian,\%Striped);

This line is also incorrect. intersection() returns a hash reference.
Its return value should be assigned to a scalar variable,
$Cats_Asian_Striped, not an array variable
print join(" ",keys %{$Cats_Asian_Striped}),"\n";

Without that fix, you would likely get another "can't use uninitialized
variable as HASH ref" here as well. (If the author had used strict, he
would have spotted this error immediately...)
This should output just tiger (the intersection of all three hashes).
Can someone please explain the syntax of the line:

What line?
I have two questions about the code:

1) The following line is where the error is generated:
my @intersection = keys %{splice @_,$i,1);
I understand what a splice does but if I understand correctly, @_
refers to the arguments passed into the subroutine. $i is initialized
to 0 at the beginning of the script and then gets set to the smallest
array.

No, it gets set to the *index* of the smallest hash. Or at least, it
*will*, once you fix the code by putting that assignment of $i and
$isize back into the for loop where it belongs.
This should be @Striped

%Striped. It's a hash, not an array.
, which is equal to 2. Thus
splice(@_,2,1) looks to me like it will remove the @Striped from @_??

Yes, but that's only half the point. In addition to removing elements
from the array, splice also *returns* the elements it removes.
Therefore, the %{ } syntax surrounding the splice call will dereference
the hashref that splice removes.

The hash is removed so that when the while loop iterates through @_
later (shift operates on @_ by default), it will not try to reprocess
this hash.
How can I fix this to eliminate the error?

See above.
2) What kind of data structure is the following line:
@Cats{qw(cat lion tiger)} = ();
It start with an array symbol but the parenthese look like it is
initialized to zero elements??

It is a hash slice. Much like you refer to a single element of a hash
%Cats like:
$Cats{'cat'}
you can refer to several elements of the hash as:
@Cats{'cat', 'lion', 'tiger'};

This is a bizarre way of intializing several keys of a hash all to the
value of undef. It would, in my opinion, be more clearly written:
my %Cats;
$Cats{$_} = undef for qw/cat lion tiger/;
Thank you for your help

You're welcome.

Paul Lalli

Thank you very much for your help. The script now runs as expected.
Here is the revised code:
#! /usr/bin/perl -w

sub intersection
{
my($i,$sizei) = (0,scalar keys%{$_[0]});
my($j,$sizej);


for($j=1;$j<@_;$j++)
{
$sizej = scalar keys %{$_[$j]};
($i,$sizei) = ($j,$sizej) if $sizej < $sizei;
}

print $i,"\n";
print $j,"\n";
my @intersection = keys %{splice @_,$i,1};
print join(" ",@intersection);
print " ";
my $set;
while($set = shift)
{
@intersection = grep {exists $set->{$_}} @intersection;

}

print join(" ",@intersection);
my %intersection;
@intersection {@intersection} = ();


return \%intersection;



}


@Cats{qw(cat lion tiger)} = ();
@Asian{qw(tiger panda yak)} = ();
@Striped{qw(zebra tiger)} = ();

$Cats_Asian_Striped = intersection(\%Cats,\%Asian,\%Striped);

print "\n";
print "Intersection of three sets is: ",keys
%{$Cats_Asian_Striped},"\n";

The last line prints "Intersection of three sets is: tiger". As tiger
can be found in all three arrays. It looks like I had some issues in
understanding hash slices.

Thanks again
 

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,764
Messages
2,569,567
Members
45,041
Latest member
RomeoFarnh

Latest Threads

Top