I have a problem accessing variables in a hash of hashes I don't know what I have done wrong. While debugging the value of hash %list1 gives an undef, So I can't get my values out .
use strict ;
use warnings ;
my $text = "The, big, fat, little, bastards";
my $Author = "Alex , Shuman ,Directory";
my %hashes = {1,2,3,40};
my %count = ();
my #lst = split(",",$text);
my $i = 0 ;
my #Authors = split(",", $Author);
foreach my $SingleAuthor(#Authors)
{
foreach my $dig (#lst)
{
$count{$SingleAuthor}{$dig}++;
}
}
counter(\%count);
sub counter
{
my $ref = shift;
my #SingleAuthors = keys %$ref;
my %list1;
foreach my $SingleAuthor1(#SingleAuthors)
{
%list1 = $ref->{$SingleAuthor1};
foreach my $dig1 (keys %list1)
{
print $ref->{$SingleAuthor1}->{$dig1};
}
}
}
In two places you are attempting to assign a hash reference to a hash, which results in this warning: Reference found where even-sized list expected.
Here are two edits you need:
# I changed {} to ().
# However, you never use %hashes, so I'm not sure why it's here at all.
my %hashes = (1,2,3,40);
# I added %{} around the right-hand side.
%list1 = %{$ref->{$SingleAuthor1}};
See perlreftut for a useful and brief discussion of complex data structures.
For what it's worth, your counter() method could be simplified without loss of readability by dropping the intermediate variables.
sub counter {
my $tallies = shift;
foreach my $author (keys %$tallies) {
foreach my $dig (keys %{$tallies->{$author}}) {
print $tallies->{$author}{$dig}, "\n";
}
}
}
Or, as ysth points out, like this if you don't need the keys:
foreach my $author_digs (values %$tallies) {
print $dig, "\n" for values %$author_digs;
}
When I ran your code, Perl told me exactly what the problem was.
$ ./hash
Reference found where even-sized list expected at ./hash line 7.
Reference found where even-sized list expected at ./hash line 30.
Use of uninitialized value in print at ./hash line 34.
Reference found where even-sized list expected at ./hash line 30.
Use of uninitialized value in print at ./hash line 34.
Reference found where even-sized list expected at ./hash line 30.
Use of uninitialized value in print at ./hash line 34.
If that's unclear, you can turn on diagnostics to get more detailed descriptions.
$ perl -Mdiagnostics hash
Reference found where even-sized list expected at hash line 7 (#1)
(W misc) You gave a single reference where Perl was expecting a list
with an even number of elements (for assignment to a hash). This usually
means that you used the anon hash constructor when you meant to use
parens. In any case, a hash requires key/value pairs.
%hash = { one => 1, two => 2, }; # WRONG
%hash = [ qw/ an anon array / ]; # WRONG
%hash = ( one => 1, two => 2, ); # right
%hash = qw( one 1 two 2 ); # also fine
Related
Please what is the difference between these two hash initialization methods?
The First Method:
$items{"food"} = "4.4";
$items{"water"} = "5.0";
$items{"shelter"} = "1.1";
foreach $item (keys $items) {
print "$item\n";
}
The output is:
food
water
shelter
The Second Method:
%items = {
'food' => '4.4',
'water' => '5.0',
'shelter' => '1.1'
};
foreach $item (keys %items) {
print "$item\n";
}
The output is a hash reference:
HASH(0x8cc41bc)
Why does the second method return a reference instead of the actual values?
Because you have misunderstood what {} does.
It creates an anonymous hash, returning a reference.
What you've just done is functionally similar to:
my %stuff = (
'food' => '4.4',
'water' => '5.0',
'shelter' => '1.1'
);
my %items = \%stuff;
Which doesn't make a lot of sense.
Use () to init the hash, and it'll work just fine.
This is a good example of why you should always turn on warnings in your Perl code.
$ perl -Mwarnings -E'%h = {}; say keys %h'
Reference found where even-sized list expected at -e line 1.
HASH(0xbb6d48)
For more detailed explanation, use "diagnostics" too.
$ perl -Mwarnings -Mdiagnostics -E'%h = {}; say keys %h'
Reference found where even-sized list expected at -e line 1 (#1)
(W misc) You gave a single reference where Perl was expecting a list
with an even number of elements (for assignment to a hash). This usually
means that you used the anon hash constructor when you meant to use
parens. In any case, a hash requires key/value pairs.
%hash = { one => 1, two => 2, }; # WRONG
%hash = [ qw/ an anon array / ]; # WRONG
%hash = ( one => 1, two => 2, ); # right
%hash = qw( one 1 two 2 ); # also fine
HASH(0x253ad48)
I want to make a subroutine that adds elements (keys with values) to a previously-defined hash. This subroutine is called in a loop, so the hash grows. I don’t want the returning hash to overwrite existing elements.
At the end, I would like to output the whole accumulated hash.
Right now it doesn’t print anything. The final hash looks empty, but that shouldn’t be.
I’ve tried it with hash references, but it does not really work. In a short form, my code looks as follows:
sub main{
my %hash;
%hash=("hello"=>1); # entry for testing
my $counter=0;
while($counter>5){
my(#var, $hash)=analyse($one, $two, \%hash);
print ref($hash);
# try to dereference the returning hash reference,
# but the error msg says: its not an reference ...
# in my file this is line 82
%hash=%{$hash};
$counter++;
}
# here trying to print the final hash
print "hash:", map { "$_ => $hash{$_}\n" } keys %hash;
}
sub analyse{
my $one=shift;
my $two=shift;
my %hash=%{shift #_};
my #array; # gets filled some where here and will be returned later
# adding elements to %hash here as in
$hash{"j"} = 2; #used for testing if it works
# test here whether the key already exists or
# otherwise add it to the hash
return (#array, \%hash);
}
but this doesn’t work at all: the subroutine analyse receives the hash, but its returned hash reference is empty or I don’t know. At the end nothing got printed.
First it said, it's not a reference, now it says:
Can't use an undefined value as a HASH reference
at C:/Users/workspace/Perl_projekt/Extractor.pm line 82.
Where is my mistake?
I am thankful for any advice.
Arrays get flattened in perl, so your hashref gets slurped into #var.
Try something like this:
my ($array_ref, $hash_ref) = analyze(...)
sub analyze {
...
return (\#array, \#hash);
}
If you pass the hash by reference (as you're doing), you needn't return it as a subroutine return value. Your manipulation of the hash in the subroutine will stick.
my %h = ( test0 => 0 );
foreach my $i ( 1..5 ) {
do_something($i, \%h);
}
print "$k = $v\n" while ( my ($k,$v) = each %h );
sub do_something {
my $num = shift;
my $hash = shift;
$hash->{"test${num}"} = $num; # note the use of the -> deference operator
}
Your use of the #array inside the subroutine will need a separate question :-)
The below one the code.
sub max
{
if (#_[0] > #_[1])
{
#_[0];
}
else
{
#_[1];
}
}
print "biggest is ".&max(37,25);
When I ran it, I got the following warnings,
Scalar values #_[0] better written as $_[0] at file.pl line 3.
Scalar values #_[1] better written as $_[1] at file.pl line 3.
Scalar values #_[0] better written as $_[0] at file.pl line 5.
Scalar values #_[0] better written as $_[0] at file.pl line 9.
biggest is 37.
Although I got a correct output, but I wonder what could be the reason behind this warning, Since I think that using #_ in a subroutine would be apropriate than $_.
The problem is that you are referring to your single array element by using an array slice instead of a scalar. Just like the error says. An array slice is a list of elements from an array, for example:
my #a = (0 .. 9);
print #a[0,3,4]; # prints 034
Conversely, when you refer to a single array element you use the scalar prefix $:
print $a[3]; # prints 3
So when you do
#_[0];
Perl is telling you that the proper way to refer to a scalar value is by not using an array slice, but rather to use the scalar notation:
$_[0];
That is all.
Try to understand it with this example:
#array = (1,2,3); #array is the name of the array and # means that it's an array
print $array[1];
#this will print element at index 1 and you're doing it in scalar context
Similarly,
#_ = (1,2,3); #_ is the name of the array
print $_[1];
#this will print element at index 1 of array _ and again you're doing it in scalar context
You are referring to an array, instead of a scalar. #_[0] means ($_[0]). But perl is kind of clever so it warns You that instead of an explicit single element list You should return a scalar. Here You should use $_[0].
I suggest to use prototype, as now You could call max (1, 2, 3) and the result will be 2, instead of 3. So define as
sub max ($$) { $_[0] > $_[1]) ? $_[0] : $_[1] }
Or better, You can use for undefined number (>=2) of elements. Maybe pointless to call it with 0 or 1 items.
sub max (#) {
return undef if $#_<0;
my $s = shift;
for(#_) { $s = $_ if $_ > $s } $s
}
Folks,
As far as my understanding goes, exists function would check for existence of a key in a hash. So for the below mentioned situation, key1 or key2 have not been defined. Going by that the hash reference $var has no keys.
In which case upon calling keys(%{$var}) should return undef.
HOWEVER, its returning 1. How..what am I missing here ?
my $var;
if (exists $var->{key1}->{key2}) {
$var->{key1}->{key2} = 1;
}
my $keys = keys(%{$var});
print $keys; #prints 1 to output console
The fact that you're checking $var->{key1}->{key2} creates $var->{key1} as empty hashref. This can be seen by doing:
use Data::Dumper;
my $var = {};
if (exists $var->{key1}->{key2}) {
print "cannot happen\n"
}
print Dumper($var);
Which prints:
$VAR1 = {
'key1' => {}
};
So, the scalar of keys is 1, because there is one key.
This is autovivification. Note that you can disable autovivification for your whole script, or for a particular lexical scope, by using the no autovification; pragma.
Can someone finish this for me and explain what you did?
my %hash;
#$hash{list_ref}=[1,2,3];
#my #array=#{$hash{list_ref}};
$hash{list_ref}=\[1,2,3];
my #array=???
print "Two is $array[1]";
#array = #{${$hash{list_ref}}};
(1,2,3) is a list.
[1,2,3] is a reference to a list an array (technically, there's no such thing in Perl as a reference to a list).
\[1,2,3] is a reference to a reference to an array.
$hash{list_ref} is a reference to a reference to an array.
${$hash{list_ref}} is a reference to an array.
#{${$hash{list_ref}}} is an array.
Since a reference is considered a scalar, a reference to a reference is a scalar reference, and the scalar dereferencing operator ${...} is used in the middle step.
Others have pretty much already answered the question, but more generally, if you are ever confused about a data structure, use Data::Dumper. This will print out the structure of the mysterious blob of data, and help you parse it.
use strict; #Always, always, always
use warnings; #Always, always, always
use feature qw(say); #Nicer than 'print'
use Data::Dumper; #Calling in the big guns!
my $data_something = \[1,2,3];
say Dumper $data_something;
say Dumper ${ $data_something };
Let's see what it prints out...
$ test.pl
$VAR1 = \[
1,
2,
3
];
$VAR1 = [
1,
2,
3
];
From the first dump, it appears that $data_something is a plain scalar reference to an array reference. That lead me to add the second Dumper after I ran the program the first time. That showed me that ${ $data_something } is now a reference to an array.
I can now access that array like this:
use strict; #Always, always, always
use warnings; #Always, always, always
use feature qw(say); #Nicer than 'print'
use Data::Dumper; #Calling in the big guns!
my $data_something = \[1,2,3];
# Double dereference
my #array = #{ ${ $data_something } }; #Could be written as #$$data_something
for my $element (#array) {
say "Element is $element";
}
And now...
$ test.pl
Element is 1
Element is 2
Element is 3
It looks like you meant:
my $hash{list_ref} = [1,2,3];
and not:
$hash{list_ref} = \[1,2,3];
That latter one got you an scalar reference of a array reference which really doesn't do you all that much good except add confusion to the situation.
Then, all you had to do to refer to a particular element is $hash{list_ref}->[0]. This is just a shortcut for ${ $hash{list_ref} }[0]. It's easier to read and understand.
use strict;
use warnings;
use feature qw(say);
my %hash;
$hash{list_ref} = [1, 2, 3];
foreach my $element (0..2) {
say "Element is " . $hash{list_ref}->[$element];
}
And...
$ test.pl
Element is 1
Element is 2
Element is 3
So, next time you are confused about what a particular data structure looks like (and it happens to the best of us. Well... not the best of us, It happens to me), use Data::Dumper.
my %hash;
#$hash{list_ref}=[1,2,3];
#Putting the list in square brackets makes it a reference so you don't need '\'
$hash{list_ref}=[1,2,3];
#If you want to use a '\' to make a reference it is done like this:
# $something = \(1,2,3); # A reference to a list
#
# or (as I did above)...
#
# $something = [1,2,3]; # Returns a list reference
#
# They are the same (for all intent and purpose)
print "Two is $hash{list_ref}->[1]\n";
# To make it completely referenced do this:
#
# $hash = {};
# $hash->{list_ref} = [1,2,3];
#
# print $hash->{list_ref}[1] . "\n";
To get at the array (as an array or list) do this:
my #array = #{ $hash{list_ref} }
[ EXPR ]
creates an anonymous array, assigns the value returned by EXPR to it, and returns a reference to it. That means it's virtually the same as
do { my #anon = ( EXPR ); \#anon }
That means that
\[ EXPR ]
is virtually the same as
do { my #anon = ( EXPR ); \\#anon }
It's not something one normally sees.
Put differently,
1,2,3 returns a list of three elements (in list context).
(1,2,3) same as previous. Parens simply affect precedence.
[1,2,3] returns a reference to an array containing three elements.
\[1,2,3] returns a reference to a reference to an array containing three elements.
In practice:
my #data = (1,2,3);
print #data;
my $data = [1,2,3]; $hash{list_ref} = [1,2,3];
print #{ $data }; print #{ $hash{list_ref} };
my $data = \[1,2,3]; $hash{list_ref} = \[1,2,3];
print #{ ${ $data } }; print #{ ${ $hash{list_ref} } };