Reputation: 45
I have found a couple of ways to copy the elements of a list to the keys of a hash, but could somebody please explain how this works?
#!/usr/bin/perl
use v5.34.0;
my @arry = qw( ray bill lois shirly missy hank );
my %hash;
$hash{$_}++ for @arry; # What is happening here?
foreach (keys %hash) {
say "$_ => " . $hash{$_};
}
The output is what I expected. I don't know how the assignment is being made.
hank => 1
shirly => 1
missy => 1
bill => 1
lois => 1
ray => 1
Upvotes: 4
Views: 191
Reputation: 67910
$hash{$_}++ for @array;
Can also be written
for (@array) {
$hash{$_}++;
}
Or more explicitly
for my $key (@array) {
$hash{$key}++;
}
$_
is "the default input and pattern-searching space"-variable. Often in Perl functions, you can leave out naming an explicit variable to use, and it will default to using $_
. for
is an example of that. You can also write an explicit variable name, that might feel more informative for your code:
for my $word (@words)
Or idiomatically:
for my $key (keys %hash) # using $key variable name for hash keys
You should also be aware that for
and foreach
are exactly identical in Perl. They are aliases for the same function. Hence, I always use for
because it is shorter.
The second part of the code is the assignment, using the auto-increment operator ++
It is appended to a variable on the LHS and increments its value by 1. E.g.
$_++ means $_ = $_ + 1
$hash{$_}++ means $hash{$_} = $hash{$_} + 1
...etc
It also has a certain Perl magic included, which you can read more about in the documentation. In this case, it means that it can increment even undefined variables without issuing a warning about it. This is ideal when it comes to initializing hash keys, which do not exist beforehand.
Your code will initialize a hash key for each word in your @arry
list, and also count the occurrences of each word. Which happens to be 1 in this case. This is relevant to point out, because since hash keys are unique, your array list may be bigger than the list of keys in the hash, since some keys would overwrite each other.
my @words = qw(foo bar bar baaz);
my %hash1;
for my $key (@words) {
$hash{$key} = 1; # initialize each word
}
# %hash1 = ( foo => 1, bar => 1, baaz => 1 );
# note -^^
my %hash2; # new hash
for my $key (@words) {
$hash{$key}++; # use auto-increment: words are counted
}
# %hash2 = ( foo => 1, bar => 2, baaz => 1);
# note -^^
Upvotes: 6
Reputation: 66954
Here is another one
my %hash = map { $_ => 1 } @ary;
Explanation: map takes an element of the input array at a time and for each prepapres a list, here of two -- the element itself ($_
, also quoted because of =>) and a 1
. Such a list of pairs then populates a hash, as a list of an even length can be assigned to a hash, whereby each two successive elements form a key-value pair.
Note: This does not account for possibly multiple occurences of same elements in the array but only builds an existance-check structure (whether an element is in the array or not).
Upvotes: 4
Reputation: 16817
$hash{$_}++ for @arry; # What is happening here?
Read perlsyn, specifically simple statements and statement modifiers:
The only kind of simple statement is an expression evaluated for its side-effects. Every simple statement must be terminated with a semicolon, unless it is the final statement in a block, in which case the semicolon is optional. But put the semicolon in anyway if the block takes up more than one line, because you may eventually add another line. Note that there are operators like eval {}
, sub {}
, and do {}
that look like compound statements, but aren't--they're just TERMs in an expression--and thus need an explicit termination when used as the last item in a statement.
Any simple statement may optionally be followed by a SINGLE modifier, just before the terminating semicolon (or block ending). The possible modifiers are:
if EXPR
unless EXPR
while EXPR
until EXPR
for LIST
foreach LIST
when EXPR
[...]
The for(each)
modifier is an iterator: it executes the statement once for each item in the LIST (with $_
aliased to each item in turn). There is no syntax to specify a C-style for loop or a lexically scoped iteration variable in this form.
print "Hello $_!\n" for qw(world Dolly nurse);
Upvotes: 2
Reputation: 9306
$hash{$_}++ for @arry; # What is happening here?
It is iterating over the array, and for each element, it's assigning it as a key to the hash, and incrementing the value of that key by one. You could also write it like this:
my %hash;
my @array = (1, 2, 2, 3);
for my $element (@array) {
$hash{$element}++;
}
The result would be:
$VAR1 = {
'2' => 2,
'1' => 1,
'3' => 1
};
Upvotes: 2