如何在Perl中获得哈希的一部分?

isr3a4wc  于 6个月前  发布在  Perl
关注(0)|答案(7)|浏览(96)

有没有办法得到一个子哈希值?我需要使用哈希切片吗?
举例来说:

%hash = ( a => 1, b => 2, c => 3 );

字符串
我只想要

%hash = ( a => 1, b => 2 );

dy1byipe

dy1byipe1#

散列切片返回与键列表相关的值。要获得散列切片,请将sigil更改为@并提供键列表(在本例中为"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开始,如果你使用% sigil而不是@ sigil,你可以在一个步骤中获得键和值:

use v5.20;
my %new_hash = %hash{qw/a b/};

kjthegm6

kjthegm62#

你可能想要组装一个你想要的键的列表:

my @keys = qw(a b);

字符串
然后使用一个循环来生成哈希:

my %hash_slice;
for(@keys) {
  $hash_slice{$_} = %hash{$_};
}


或者:

my %hash_slice = map { $_ => $hash{$_} } @keys;


(My第二个是偏好,但你喜欢的是最好的。

sigwle7e

sigwle7e3#

另一种方式:

my @keys = qw(a b);
my %hash = (a => 1, b => 2, c => 3);
my %hash_copy;
@hash_copy{@keys} = @hash{@keys};

字符串

cvxl0en2

cvxl0en24#

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(在我的情况下,它需要一个包含用户名和密码的hashref,但没有其他内容)。

nnsrf1az

nnsrf1az5#

perl 5.20中的新功能是hash slice通过使用%来返回键和值,就像这里最后一行那样:

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!

字符串

emeijp43

emeijp436#

太多的函数式编程让我首先想到了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;


避免了mapzip解决方案带来的额外复制。(是的,在迭代时改变哈希值是安全的......只要改变只删除最近迭代的对。)

eoigrqb6

eoigrqb67#

散列是一个无序的容器,但是切片这个术语只有在有序容器中才有意义。也许可以考虑使用数组。否则,你可能只需要删除所有你不想产生“子散列”的元素。

相关问题