如何将列表元素复制到 perl 中的散列键?

How do I copy list elements to hash keys in perl?

我找到了几种将列表元素复制到散列键的方法,但有人可以解释一下这是如何工作的吗?

#!/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{$_};
}

输出符合我的预期。不知道怎么分配的。

hank => 1
shirly => 1
missy => 1
bill => 1
lois => 1
ray => 1

$hash{$_}++ for @arry; # What is happening here?

它遍历数组,对于每个元素,它都将其分配为散列的键,并将该键的值递增 1。你也可以这样写:

my %hash;
my @array = (1, 2, 2, 3);

for my $element (@array) {
    $hash{$element}++;
}

结果将是:

$VAR1 = {
          '2' => 2,
          '1' => 1,
          '3' => 1
        };

这是另一个

my %hash = map { $_ => 1 } @ary;

解释: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 =>) 和 1。这样的对列表然后填充散列,因为可以将偶数长度的列表分配给散列,由此每两个连续元素形成一个 key-value 对。


注意:这不考虑数组中相同元素可能多次出现的情况,而只是构建一个 existance-check 结构(无论元素是否在数组中)。

$hash{$_}++ for @arry;  # What is happening here?

阅读perlsyn, specifically simple statements and statement modifiers:

简单语句

唯一一种简单语句是为其 side-effects 求值的表达式。每个简单语句都必须以分号结束,除非它是块中的最后一个语句,在这种情况下分号是可选的。但是,如果该块占用多于一行,无论如何都要加上分号,因为您最终可能会添加另一行。请注意,像 eval {}sub {}do {} 这样的运算符看起来像复合语句,但实际上不是——它们只是表达式中的术语——因此需要一个当用作语句中的最后一项时显式终止。

语句修饰符

任何简单的语句都可以选择在终止分号(或块结束)之前跟一个 SINGLE 修饰符。可能的修饰符是:

if EXPR
unless EXPR
while EXPR
until EXPR
for LIST
foreach LIST
when EXPR

[...]

for(each) 修饰符是一个迭代器:它对 LIST 中的每个项目执行一次语句($_ 依次为每个项目别名)。在这种形式中没有语法来指定 C-style for 循环或词法范围内的迭代变量。

print "Hello $_!\n" for qw(world Dolly nurse);
$hash{$_}++ for @array;

也可以这样写

for (@array) {
    $hash{$_}++;
}

或更明确地说

for my $key (@array) {
    $hash{$key}++;
}

$_ 是“默认输入和 pattern-searching space”-变量。通常在 Perl 函数中,您可以省略命名要使用的显式变量,它默认使用 $_for 就是一个例子。您还可以编写一个明确的变量名,这可能会为您的代码提供更多信息:

for my $word (@words) 

或惯用语:

for my $key (keys %hash)    # using $key variable name for hash keys

您还应该知道 forforeach 在 Perl 中完全相同。它们是同一功能的别名。因此,我总是使用 for 因为它更短。

代码的第二部分赋值,使用了auto-increment operator ++

它被附加到 LHS 上的一个变量,并将其值增加 1。例如

$_++           means $_ = $_ + 1
$hash{$_}++    means $hash{$_} = $hash{$_} + 1
...etc

它还包含一定的 Perl 魔法,您可以在文档中阅读更多相关信息。在这种情况下,这意味着它甚至可以在不发出警告的情况下增加未定义的变量。这对于初始化事先不存在的哈希键非常理想。

您的代码将为 @arry 列表中的每个单词初始化一个散列键,并计算每个单词的出现次数。在这种情况下恰好是 1。需要指出的是,由于散列键是唯一的,您的数组列表可能比散列中的键列表更大,因为有些键会相互覆盖。

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 -^^