有没有办法获得子哈希?我需要使用哈希片吗?
例如:
%hash = ( a => 1, b => 2, c => 3 );
我只要
%hash = ( a => 1, b => 2 );
哈希切片返回与键列表关联的值。要获得哈希切片,请将印记更改为 @ 并提供键列表(在本例中为
"a"
和 "b"
):
my @items = @hash{"a", "b"};
通常您可以使用引号词运算符来生成列表:
my @items = @hash{qw/a b/};
您还可以分配给哈希切片,因此如果您想要一个包含另一个哈希的子集的新哈希,您可以说
my %new_hash;
@new_hash{qw/a b/} = @hash{qw/a b/};
很多人会使用 map 而不是哈希切片:
my %new_hash = map { $_ => $hash{$_} } qw/a b/;
从 Perl 5.20.0 开始,如果使用 % 印记而不是 @ 印记,您可以一步获取键和值:
my %new_hash = %hash{qw/a b/};
您可能想要组合您想要的键列表:
my @keys = qw(a b);
然后使用循环来生成哈希:
my %hash_slice;
for(@keys) {
$hash_slice{$_} = %hash{$_};
}
或者:
my %hash_slice = map { $_ => $hash{$_} } @keys;
(我的偏好是第二个,但你喜欢哪个最好。)
还有另一种方式:
my @keys = qw(a b);
my %hash = (a => 1, b => 2, c => 3);
my %hash_copy;
@hash_copy{@keys} = @hash{@keys};
FWIW,我在这里使用 Moose::Autobox:
my $hash = { a => 1, b => 2, c => 3, d => 4 };
$hash->hslice([qw/a b/]) # { a => 1, b => 2 };
在现实生活中,我使用它从表单提交中提取“用户名”和“密码”,并将其传递给 Catalyst 的
$c->authenticate
(在我的例子中,它期望包含用户名和密码的哈希引用,但没有其他内容) .
太多的函数式编程让我首先想到
zip
。
安装了List::MoreUtils,
use List::MoreUtils qw(zip);
%hash = qw(a 1 b 2 c 3);
@keys = qw(a b);
@values = @hash{@keys};
%hash = zip @keys, @values;
不幸的是,List::MoreUtils 的原型
zip
抑制了
zip @keys, @hash{@keys};
如果你真的想避免中间变量,你可以
zip @keys, @{[@hash{@keys}]};
或者只是编写自己的
zip
,而没有有问题的原型。 (这根本不需要 List::MoreUtils。)
sub zip {
my $max = -1;
$max < $#$_ and $max = $#$_ for @_;
map { my $ix = $_; map $_->[$ix], @_; } 0..$max;
}
%hash = zip \@keys, [@hash{@keys}];
如果你要就地突变,
%hash = qw(a 1 b 2 c 3);
%keep = map +($_ => 1), qw(a b);
$keep{$a} or delete $hash{$a} while ($a, $b) = each %hash;
避免了
map
和 zip
解决方案产生的额外复制。 (是的,在迭代哈希时对其进行变异是安全的......只要变异仅删除最近迭代的对。)
perl 5.20 中的新功能是哈希切片通过使用 % 返回键和值,如此处最后一行所示:
my %population = ('Norway',5000000,'Sweden',9600000,'Denmark',5500000);
my @slice_values = @population{'Norway','Sweden'}; # all perls can do this
my %slice_hash = %population{'Norway','Sweden'}; # perl >= 5.20 can do this!
哈希是无序容器,但术语切片只有在有序容器方面才真正有意义。也许考虑使用数组。否则,您可能只需要删除所有您不想生成“子哈希”的元素即可。