Different declaration of hash in Perl - perl

I know that:
my %hash = {};
gets an anonymous hash, How about this:
my %hash = %{some values}
what is the difference of that above with this?
my %hash = (some hash values);

No.
my %hash = {};
generates a warning (you turned them on, right?):
Reference found where even-sized list expected at -e line 1.
Reference is always scalar. The correct way is
my $hash_ref = {};
To dereference a reference, you can use the following syntax:
my %hash = %$hash_ref;
my %also_hash = %{$hash_ref}; # Same as above.
$hash{key} eq $hash_ref->{key} or die; # Should survive.
Moreover,
%{ some values }
generates a syntax error:
perl -we 'my $h = %{1, 2, 3, 4}'
syntax error at -e line 1, near "%{"

The difference is how you express the content of the hash.
With the array notation below, for example; you do it like this:
my %hash = ( 'key 1' => 'value 1', 'key 2' => 'value 2');
The %{ } is a cast operator. It is used typically when you have a reference to something that is not obviously a hash. Typically a reference to a has:
Example:
my $hashref;
$hashref->{'key 1'}='value 1';
$hashref->{'key 2'}='value 2';
my %hash = %{$hashref};

Related

"Not an ARRAY reference" in Perl

I'm new to Perl and trying to get used to data structures and references in Perl.
I learned
key %hash returns an array of the keys in %hash
\{ #array } returns the reference to the #array
So I combined these two and wrote something like this,
use strict;
use warnings;
use Data::Dumper;
my $hash = {
key1 => 'value1',
key2 => 'value2'
};
my $keys = \{ keys %$hash }; # Supposed to be an array reference?
print Dumper $keys; # Output 1
print Dumper $keys->[0]; # Output 2
which yielded the error Not an ARRAY reference at the line of Output 2. Also, Output 1 shows something that looks like a hash reference though it's supposed to be an array reference.
What's wrong with my code?
Similarly, the following code didn't work with the same error.
use strict;
use warnings;
my $array = [1, 2, 3, 4, 5];
my $first_two = \{ #{ $array }[0..1] }; # Isn't it an array ref?
my $first = $first_two->[0];
I guess I misunderstand something about array references.
The problem you have is this is not correct: '\{ #array } returns the reference to the #array' . Instead, the \ is simply prepended to an existing variable, like this: \#array. Braces {} are used to create anonymous hash references, and brackets [] are used to create anonymous array references.
In your example, what you want to do is either (1) store the keys as an array and then use \ to get a reference:
my #keys = keys %$hash;
my $keys = \#keys;
Or (2) use an anonymous array reference:
my $keys = [ keys %$hash ];
Here's a good "reference" ;) https://perldoc.perl.org/perlref.html#Making-References

Printing Hash Pairs in Perl

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)

Dereferencing a list reference in hash element

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} } };

What's the point of this kind of code?

{%{$self->param}}
It does hash expand, and then create another hash reference.
But isn't {%{$self->param}} the same as $self->param? Why does the code bother doing the trick?
It copies the hash. Consider the following snippet:
use Data::Dumper;
my $foo = { a => 1, ar => [1] };
my $bar = {%$foo};
$bar->{b} = 2;
push #{$bar->{ar}}, 4;
print Dumper $foo;
print Dumper $bar;
It prints
$VAR1 = {
'a' => 1,
'ar' => [
1,
4
]
};
$VAR1 = {
'a' => 1,
'b' => 2,
'ar' => [
1,
4
]
};
So you can see that the copy is shallow: Scalars are copied over, even if they are references. The referenced objects are the same (in this example the array referenced by ar).
Although both {%{$self->param}} and $self->param are references to a hash, they do not refer to a hash stored in the same location.
The first expression dereferences $self->param to a hash, and returns a reference to an anonymous hash. Within the outer braces, %{$self->param} is actually expanded and copied temporarily, and then a reference to this temporary copy is returned, not to the old hash.
This code actually creates a copy hash (shallow copy of keys and values, but not deep copy), reference to which is returned and returns reference to it.
If some sub returns reference to a hash and you change something in it, you actually are changing values in original hash. To avoid this we sometimes need to copy whole hash (or array) before making any changes.
Here's example:
sub get_hashref {
my $hashref = shift;
return $hashref;
}
my %hash = (foo => 'bar');
my $ref = get_hashref(\%hash);
$ref->{foo} = 'baz'; # Changes 'foo' value in %hash
print "Original 'foo' now is: $hash{foo}\n"; # 'baz'
print "Ref's 'foo' now is: $ref->{foo}\n"; # 'baz'
# But!
$ref = {%{ get_hashref(\%hash) }};
$ref->{foo} = 42; # No changes in %hash
print "Original 'foo' now is: $hash{foo}\n"; # 'baz'
print "Ref's 'foo' now is: $ref->{foo}\n"; # '42'
To be understood better, {%{ $self->param }} may be expanded to:
my $ref = $self->param; # Ref to original hash
my %copy = %{$ref}; # Copies keys and values to new hash
my $ref_to_copy = {%copy}; # get ref to it
You also may omit last step if you need hash but not reference to it.

Problems with hash of hashes in perl

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