如果密钥存在于%hash中,我试图将键值对放在%hash1上 数组中有一个元素,%hash没有条目 例如:@array =(1,2,3,4,5); #there在%hash
处没有密钥1的哈希条目所以我认为map会完成这项工作,我会在我的新哈希中获得4个键,即%hash1,但它会提供5个键。与此同时,我尝试了foreach并且它起作用了。我妄想我们可以用地图取代foreach,但这个案例让我思考。 谁能解释一下,我的逻辑出错了?
#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{$_});
}
答案 0 :(得分:9)
您的问题是map
表达式为undef
中的第一个元素返回 错误值。 @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
};
您正在生成一个包含奇数元素的列表。而且这并不是一个快乐的哈希。
当您构建哈希时,您需要确保拥有偶数个元素。因此,当您使用map
时,您需要为每次迭代返回零个或两个元素。所以你需要这样的东西:
#!/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'
};
答案 1 :(得分:4)
map将始终返回您在其代码块中放置的内容。所以
的返回值%hash1 = map { $_=>$hash{$_} if(exists $hash{$_}) } @array;
在$_=>$hash{$_}
存在时为$hash{$_}
,如果不存在,则为""
。
您可能想写的内容:
my %hash1 = map { exists($hash{$_}) ? ($_ => $hash{$_}) : () }
答案 2 :(得分:3)
对所提供列表中的每个值计算map
调用的块,并且块返回的值是最后一个表达式的值。
您的map
声明
my %hash1 = map { $_ => $hash{$_} if (exists $hash{$_}) } @array
相当于
my %hash1 = map {
if (exists $hash{$_}) {
$_ => $hash{$_}
}
} @array
首先评估表达式exists $hash{$_}
。然后,如果为真,则评估$_ => $hash{$_}
。
如果测试成功,则最后评估的表达式为$_ => $hash{$_}
,这是您想要的,但如果测试失败,则块返回exists $hash{$_}
的值。
exists
返回1
或""
的true或false,因此@array
中的元素不会显示为%hash
结果的键在map
返回的列表中的单个空字符串中。
如果将map
分配给数组,则更容易看到Odd number of elements in hash assignment
的结果。这样就可以避免undef
警告并自动分配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
在所有块中都有效,就像子程序中允许的那样。 {{1}}在这里已经有效,并且这是一个特定的限制,它禁止块一般退出并返回一个显式值。
答案 3 :(得分:2)
my %hash1 = map { ( $_ => $hash{$_} ) if exists($hash{$_}) } @array;
与
相同my %hash1 = map { exists($hash{$_}) and ( $_ => $hash{$_} ) } @array;
考虑exists($hash{$_})
为假时会发生什么。当没有值时,返回单个值(dualvar(0,"")
又名“假值”)。当exists
为假
my %hash1 = map { exists($hash{$_}) ? ( $_ => $hash{$_} ) : () } @array;
或者您可以将过滤移出map
my %hash1 = map { $_ => $hash{$_} } grep { exists($hash{$_}) } @array;