Perl 有人能解释为什么foreach工作而不是map吗
如果%hash中存在键,我尝试将键值对放在%hash1 数组中有一个元素在%hash处没有条目 例如:@array=(1,2,3,4,5)#在%hash处没有键1的哈希项 所以我认为map可以完成这项工作,我将在我的新哈希中得到4个键,即%hash1,但它给出了5个键。同时,我尝试了foreach,它成功了。我误以为我们可以用map替换foreach,但这个案例让我思考。 谁能解释一下,我的逻辑哪里出错了Perl 有人能解释为什么foreach工作而不是map吗,perl,hash,map,exists,Perl,Hash,Map,Exists,如果%hash中存在键,我尝试将键值对放在%hash1 数组中有一个元素在%hash处没有条目 例如:@array=(1,2,3,4,5)#在%hash处没有键1的哈希项 所以我认为map可以完成这项工作,我将在我的新哈希中得到4个键,即%hash1,但它给出了5个键。同时,我尝试了foreach,它成功了。我误以为我们可以用map替换foreach,但这个案例让我思考。 谁能解释一下,我的逻辑哪里出错了 #Method 1. Comment it while using Method 2 %h
#Method 1. Comment it while using Method 2
%hash1 = map { $_=>$hash{$_} if(exists $hash{$_}) } @array;
# Method 2. Comment whole loop while using method 1
foreach (@array){
$hash1{$_} = $hash{$_} if(exists $hash{$_});
}
您的问题是
map
表达式为@array
中的第一个元素返回了一个假值。当它被用作散列键时,它被字符串化为一个空字符串。(在注释中,Borodin指出这种解释是不正确的。事实上,空字符串来自当键为“1”时从exists
返回的假值)
如果a)打开strict
和warnings
和b)创建哈希后使用Data::Dumper
显示哈希,您可能会更好地了解正在执行的操作
#!/usr/bin/perl
use strict;
use warnings;
use 5.010;
use Data::Dumper;
my @array = (1 .. 5);
my %hash = ( 2 => 'two', 3 => 'three', 4 => 'four', 5 => 'five' );
my %hash1 = map { $_=>$hash{$_} if(exists $hash{$_}) } @array;
say Dumper \%hash1;
这表明您最终得到如下哈希:
$ ./hash
Odd number of elements in hash assignment at ./hash line 12.
$VAR1 = {
'' => 2,
'three' => 4,
'five' => undef,
'two' => 3,
'four' => 5
};
#!/usr/bin/perl
use strict;
use warnings;
use 5.010;
use Data::Dumper;
my @array = (1 .. 5);
my %hash = ( 2 => 'two', 3 => 'three', 4 => 'four', 5 => 'five' );
my %hash1 = map { exists $hash{$_} ? ($_ => $hash{$_}) : () } @array;
say Dumper \%hash1;
您正在生成一个包含奇数个元素的列表。这并不是一个快乐的杂烩
在构建散列时,需要确保元素数为偶数。因此,当您使用map
时,您需要为每个迭代返回零个或两个元素。所以你需要这样的东西:
$ ./hash
Odd number of elements in hash assignment at ./hash line 12.
$VAR1 = {
'' => 2,
'three' => 4,
'five' => undef,
'two' => 3,
'four' => 5
};
#!/usr/bin/perl
use strict;
use warnings;
use 5.010;
use Data::Dumper;
my @array = (1 .. 5);
my %hash = ( 2 => 'two', 3 => 'three', 4 => 'four', 5 => 'five' );
my %hash1 = map { exists $hash{$_} ? ($_ => $hash{$_}) : () } @array;
say Dumper \%hash1;
注意,当在第一个散列中找不到键时,我们显式返回一个空列表
$ ./hash2
$VAR1 = {
'4' => 'four',
'3' => 'three',
'2' => 'two',
'5' => 'five'
};
将始终返回您在其代码块中输入的内容。那么
%hash1 = map { $_=>$hash{$_} if(exists $hash{$_}) } @array;
当$hash{$}
存在时,将是$\u=>$hash{$\u}
,如果不存在,将是”
你可能想写的是:
my %hash1 = map { exists($hash{$_}) ? ($_ => $hash{$_}) : () }
map
调用的块针对提供的列表中的每个值进行计算,该块返回的值是最后计算的表达式的值
您的map
语句
my %hash1 = map { $_ => $hash{$_} if (exists $hash{$_}) } @array
相当于
my %hash1 = map {
if (exists $hash{$_}) {
$_ => $hash{$_}
}
} @array
因此首先计算表达式exists$hash{$}
。然后,如果为true,则计算$\=>$hash{$\}
因此,如果测试成功,则最后计算的表达式是$\u=>$hash{$\u}
,这是您想要的,但是如果测试失败,则块返回exists$hash{$\u}
的值
exists
返回1
或”
表示true或false,因此@array
中未显示为%hash
键的元素会在map
返回的列表中产生一个空字符串
如果将映射指定给数组,则更容易查看该映射的结果。这样可以避免散列赋值中出现奇数个元素的警告和自动赋值unde
散列值
如果你改写
my @arr = map { $_ => $hash{$_} if (exists $hash{X}) } @array;
(即测试总是失败)结果与
my @arr = map { exists $hash{X} } @array;
或者只是
("", "", "", "")
使用map
编写此函数的方法是使用条件运算符,以便在条件失败时返回空列表
my %hash1 = map { exists $hash{$_} ? ( $_ => $hash{$_} ) : () } @array
我相信您不需要解释为什么您的foreach
循环工作
我相信return
在所有块中都是有效的,就像在子例程中一样wantarray
在这里已经有效,这是一个特定的限制,通常禁止块退出并返回显式值
my %hash1 = map { ( $_ => $hash{$_} ) if exists($hash{$_}) } @array;
是同一件事吗
my %hash1 = map { exists($hash{$_}) and ( $_ => $hash{$_} ) } @array;
考虑当存在($hash{$\u})
为false时会发生什么。当不应返回任何值时,将返回单个值(dualvar(0,”)
aka“false值”)。如果存在
为false,则可以更改表达式以返回空列表
my %hash1 = map { exists($hash{$_}) ? ( $_ => $hash{$_} ) : () } @array;
或者,您可以将筛选从映射中移出
my %hash1 = map { $_ => $hash{$_} } grep { exists($hash{$_}) } @array;
非常快速且非常准确。您关于将unde
字符串化为空字符串的解释是错误的。您看到的空字符串是不存在键的exists$hash{$\u}
的值<代码>未定义
如果不使用未初始化值
警告噪声,将不会转换为空字符串。map和grep:D的良好组合。谢谢