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

Posted

技术标签:

【中文标题】如何在 Perl 中获取哈希的一部分?【英文标题】:How can I get a only part of a hash in Perl? 【发布时间】:2010-11-02 00:41:57 【问题描述】:

有没有办法获得子哈希?我需要使用哈希切片吗?

例如:

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

我只想要

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

【问题讨论】:

由于逻辑上没有什么可以“切片”的,我怀疑与“地图”有关。在数组中,您将基于索引来执行此操作,但在哈希中,其中的数据没有可靠的内部表示。您需要某种类型的限定符(正则表达式?)来定义什么应该进入 subhash,什么不应该。 顺便说一句,您的哈希语法错误:使用圆括号“()”表示普通哈希,“”表示匿名哈希引用。 【参考方案1】:

Hash slices 返回与键列表关联的值。要获得哈希切片,您需要将 sigil 更改为 @ 并提供键列表(在本例中为 "a""b"):

my @items = @hash"a", "b";

您通常可以使用引号单词运算符来生成列表:

my @items = @hashqw/a b/;

你也可以分配给一个散列片,所以如果你想要一个包含另一个散列子集的新散列,你可以说

my %new_hash;
@new_hashqw/a b/ = @hashqw/a b/;

很多人会使用map 代替哈希切片:

my %new_hash = map  $_ => $hash$_  qw/a b/;

从 Perl 5.20.0 开始,如果使用 % sigil 而不是 @sigil,则可以一步获取键和值:

my %new_hash = %hashqw/a b/;

【讨论】:

这让我更清楚为什么“map”可以使用哈希值。谢谢 拉里·沃尔、布赖恩·德·福伊和……查斯。欧文斯...感谢您提供如此全面的解释! 您可能应该更清楚地说明哈希切片只有值,而不是键/值对。【参考方案2】:

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

my @keys = qw(a b);

然后使用循环来做哈希:

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

或者:

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

(我更喜欢第二个,但你喜欢哪个最好。)

【讨论】:

【参考方案3】:

另一种方式:

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

【讨论】:

【参考方案4】:

太多的函数式编程让我首先想到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 解决方案产生的额外复制。 (是的,在迭代哈希时对其进行变异是安全的……只要变异只删除最近迭代的对。)

【讨论】:

请解释一下 -- %keep = map +($_ =&gt; 1), qw(a b); ?【参考方案5】:

FWIW,我在这里使用 Moose::Autobox:

my $hash =  a => 1, b => 2, c => 3, d => 4 ;
$hash->hslice([qw/a b/]) #  a => 1, b => 2 ;

在现实生活中,我使用它从表单提交中提取“用户名”和“密码”,并将其传递给 Catalyst 的 $c-&gt;authenticate(在我的情况下,它期望包含用户名和密码的 hashref,但没有否则)。

【讨论】:

$hash->hslice(qw/a b/) 比 @$hashqw/a b/ 好多少?或者这是其中一种情况,如果我不得不问,我就太远了,无法理解? 您应该有一个答案模板,以便“我使用 Moose::”在每个答案的开头。 :) 查斯。 Owens:这不是 hslice 所做的。 @$hash... 返回值列表; hslice 返回一个包含键和值的新哈希引用。【参考方案6】:

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!

【讨论】:

【参考方案7】:

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

【讨论】:

在 Perl 中,散列切片很有用并且得到完全支持。要了解更多信息,请重新阅读the 'Slices' section in perldata

以上是关于如何在 Perl 中获取哈希的一部分?的主要内容,如果未能解决你的问题,请参考以下文章

在 Perl 中如何使用变量作为哈希键?

如何在 Perl 哈希表中存储多个值?

如何将数组作为值存储在 Perl 哈希中?

如何在perl中删除哈希值中的重复值?

在 Perl 中将 MySQL 结果作为哈希表返回

在 Perl 中,如何从子例程返回绑定的哈希?