Perl newb here, sorry for a silly question, but googling -> for a coding context is tough... Sometimes, I will access a hash like this: $hash{key} and sometimes that doesn't work, so I access it like this $hash->{key}. What's going on here? Why does it work sometimes one way and not the other?
The difference is that in the first case %hash is a hash, and in the second case, $hash is a reference to a hash (= hash reference), thus you need different notations. In the second case -> dereferences $hash.
EXAMPLES:
# %hash is a hash:
my %hash = ( key1 => 'val1', key2 => 'val2');
# Print 'val1' (hash value for key 'key1'):
print $hash{key1};
# $hash_ref is a reference to a hash:
my $hash_ref = \%hash;
# Print 'val1' (hash value for key 'key1', where the hash
# in pointed to by the reference $hash_ref):
print $hash_ref->{key1};
# A copy of %hash, made using dereferencing:
my %hash2 = %{$hash_ref}
# $hash_ref is an anonymous hash (no need for %hash).
# Note the { curly braces } :
my $hash_ref = { key1 => 'val1', key2 => 'val2' };
# Access the value of anonymous hash similarly to the above $hash_ref:
# Print 'val1':
print $hash_ref->{key1};
SEE ALSO:
perlreftut: https://perldoc.perl.org/perlreftut.html
Related
I have this code where array is an array of hashes:
my $hash = $array[0];
print "REF: " . ref($hash) . "\n";
my #names = keys ($hash);
The REF prints HASH so I know it is a hash.
But then the keys function returns an error:
Type of arg 1 to keys must be hash
How can I use the $hash as a hash?
Thanks!
$hash isn't a hash, it's a hash reference. Therefore you need to dereference it before you can run keys on it.
Simplest way of doing this:
keys %$hash;
e.g.
foreach my $key ( keys %$hash ) {
print $key, " => ", $hash -> {$key},"\n";
}
And yes, I am mixing two dereference methods deliberately. The -> notation says 'dereference this' - it's commonly used for object oriented stuff.
For more complex dereferencing %$hash{'key'} is ambiguous, so you start needing brackets - %{$hash{'key'}} for example.
See:
http://perldoc.perl.org/perlreftut.html
http://perldoc.perl.org/perlref.html
I want to know the following code why print "2/8".
#!/usr/bin/perl
#use strict;
#use warnings;
%a = ('a'=>'dfsd','b'=>'fdsfds');
print %a."\n";
You are printing a hash in scalar context by concatenating it with a string '\n'
If you evaluate a hash in scalar context, it returns false if the hash
is empty. If there are any key/value pairs, it returns true; more
precisely, the value returned is a string consisting of the number of
used buckets and the number of allocated buckets, separated by a
slash.
2/8 means that of the 8 buckets allocated, 2 have been touched. Considering that you've inserted only 2 values, it is doing well so far :)
The value is obviously of no use, except to evaluate how well the hash-function is doing. Use print %a; to print its contents.
As mentioned by #Dark.. you are printing a hash in scalar context.
if you really want to print a hash, then use Data::Dumper
use Data::Dumper;
...
...
print Dumper(%a);
for eg:
use Data::Dumper;
my %hash = ( key1 => 'value1', key2 => 'value2' );
print Dumper(%hash); # okay, but not great
print "or\n";
print Dumper(\%hash); # much better
And the output:
$VAR1 = 'key2';
$VAR2 = 'value2';
$VAR3 = 'key1';
$VAR4 = 'value1';
or
$VAR1 = {
'key2' => 'value2',
'key1' => 'value1'
};
I have the following hash, and I wish to keep it in the order I've set it in; is this even possible? If not, do any alternatives exist?
my %hash = ('Key1' => 'Value1', 'Key2' => 'Value2', 'Key3' => 'Value3');
Do I need to write a custom sorting subroutine? What are my options?
Thank you!
http://metacpan.org/pod/Tie::IxHash
use Tie::IxHash;
my %hash;
tie %hash,'Tie::IxHash';
This hash will maintain its order.
See Tie::Hash::Indexed. Quoting its Synopsis:
use Tie::Hash::Indexed;
tie my %hash, 'Tie::Hash::Indexed';
%hash = ( I => 1, n => 2, d => 3, e => 4 );
$hash{x} = 5;
print keys %hash, "\n"; # prints 'Index'
print values %hash, "\n"; # prints '12345'
Try doing this :
print "$_=$hash{$_}\n" for sort keys %hash;
if you want it sorted in alphabetic order.
If you need to retain original order, see other posts.
See http://perldoc.perl.org/functions/sort.html
One possibility is to do the same as you sometimes do with arrays: specify the keys.
for (0..$#a) { # Sorted array keys
say $a[$_];
}
for (sort keys %h) { # Sorted hash keys
say $h{$_};
}
for (0, 1, 3) { # Sorted array keys
say $h{$_};
}
for (qw( Key1 Key2 Key3 )) { # Sorted hash keys
say $h{$_};
}
You can also fetch the ordered values as follows:
my #values = #h{qw( Key1 Key2 Key3 )};
This depends on how you're going to access the data. If you just want to store them and access the last/first values, you can always put hashes in an array and use push() and pop().
#!/usr/bin/env perl
use strict;
use warnings;
use v5.10;
use Data::Dumper;
my #hashes;
foreach( 1..5 ){
push #hashes, { "key $_" => "foo" };
}
say Dumper(\#hashes);
Say I have a hash that I can index as:
$hash{$document}{$word}
From what I read online (although I could not find this on perlreftut, perldsc or perllol), I can slice a hash using a list if I use the # prefix on my hash to indicate that I want the hash to return a list. However, if I try to slice my hash using a list #list:
#%hash{$document}{#list}
I get several "Scalar values ... better written" errors.
How can I slash a nested hash in Perl?
The sigill for your hash must be #, like so:
#{$hash{$document}}{#list}
Assuming #list contains valid keys for %hash it will return the corresponding values, or undef if the key does not exist.
This is based on the general rule of a hash slice:
%foo = ( a => 1, b => 2, c => 3 );
print #foo{'a','b'}; # prints 12
%bar = ( foo => \%foo ); # foo is now a reference in %bar
print #{ $bar{foo} }{'a','b'}; # prints 12, same data as before
First, when you expect to get a list from a hash slice, use # sigil first. % is pointless here.
Second, you should understand that $hash{$document} value is not a hash or array. It's a reference - to a hash OR to an array.
With all this said, you might use something like this:
#{ $hash{$document} }{ #list };
... so you dereference value of $hash{$document}, then use a hash slice over it. For example:
my %hash = (
'one' => {
'first' => 1,
'second' => 2,
},
'two' => {
'third' => 3,
'fourth' => 4,
}
);
my $key = 'one';
my #list = ('first', 'second');
print $_, "\n" for #{ $hash{$key} }{#list};
# ...gives 1\n2\n
{%{$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.