在Perl中将具有相同键的散列值转换为数组的散列
我需要在perl中将散列转换为数组的散列 我有:在Perl中将具有相同键的散列值转换为数组的散列,perl,data-structures,hashtable,associative-array,perl-data-structures,Perl,Data Structures,Hashtable,Associative Array,Perl Data Structures,我需要在perl中将散列转换为数组的散列 我有: %hash = ( tinku => 15, tina => 4, rita => 18, tinku => 18, tinku => 17, tinku => 16, rita => 19 ); 我想把它改成: %hash = ( tinku => [ 15, 16, 17, 18 ], rita => [ 18, 19 ],
%hash = (
tinku => 15,
tina => 4,
rita => 18,
tinku => 18,
tinku => 17,
tinku => 16,
rita => 19
);
我想把它改成:
%hash = ( tinku => [ 15, 16, 17, 18 ], rita => [ 18, 19 ], tina => 4 );
你一开始就不能吃那种杂烩。Perl中的散列必须具有唯一的键。首先不能具有该散列。Perl中的散列必须具有唯一的键。你在要求不可能的东西!哈希只能有唯一的键,因此在您的示例中,您将生成一个哈希,该哈希将每个唯一名称作为其键,并将每个键的最后一个值作为其值:
#!/usr/bin/perl
use warnings;
use strict;
use Data::Dumper;
my %hash = (tinku =>15,tina =>4, rita =>18,
tinku =>18, tinku =>17, tinku =>16, rita =>19);
print Dumper \%hash;
要对数组进行散列,可以尝试以下操作:
my %hash;
my @names = qw(tinku tina rita tinku tinku tinku rita);
my @nums = qw(15 4 18 18 17 16 19);
push @{ $hash{ $names[$_] } }, $nums[$_] for 0 .. $#names;
print Dumper \%hash;
你在要求不可能的事!哈希只能有唯一的键,因此在您的示例中,您将生成一个哈希,该哈希将每个唯一名称作为其键,并将每个键的最后一个值作为其值:
#!/usr/bin/perl
use warnings;
use strict;
use Data::Dumper;
my %hash = (tinku =>15,tina =>4, rita =>18,
tinku =>18, tinku =>17, tinku =>16, rita =>19);
print Dumper \%hash;
要对数组进行散列,可以尝试以下操作:
my %hash;
my @names = qw(tinku tina rita tinku tinku tinku rita);
my @nums = qw(15 4 18 18 17 16 19);
push @{ $hash{ $names[$_] } }, $nums[$_] for 0 .. $#names;
print Dumper \%hash;
此赋值只保留每个键的最后一个值(即tinku=>16,rita=>19,tina=>4),并忽略前面的值。这样做是为了允许在散列赋值中重写值。例如
sub some_function {
my %args = (%sane_defaults, @_);
};
而且,(foo=>(1,2,3))将创建散列(foo=>1,2=>3),而不是您所期望的
一个可能的解决办法是:
use strict;
use warnings;
use Data::Dumper;
my @array = (tinku =>15,tina =>4, rita =>18, tinku =>18,
tinku =>17, tinku =>16, rita =>19);
my %hash = hash_of_arrays( @array );
print Dumper(\%hash);
sub hash_of_arrays {
die "Odd number of elements in hash (of arrays) assignment"
if @_ % 2;
# I never understood why this is a *warning* :-)
# populate hash by hand
my %hash;
while (@_) {
my $key = shift;
my $value = shift;
push @{ $hash{$key} }, $value;
# here hash values automatically become
# empty arrayrefs if not defined, thanks Larry
};
return %hash;
# *tecnically*, this one returns *array*
# and converts it back to hash
};
此赋值只保留每个键的最后一个值(即tinku=>16,rita=>19,tina=>4),并忽略前面的值。这样做是为了允许在散列赋值中重写值。例如
sub some_function {
my %args = (%sane_defaults, @_);
};
而且,(foo=>(1,2,3))将创建散列(foo=>1,2=>3),而不是您所期望的
一个可能的解决办法是:
use strict;
use warnings;
use Data::Dumper;
my @array = (tinku =>15,tina =>4, rita =>18, tinku =>18,
tinku =>17, tinku =>16, rita =>19);
my %hash = hash_of_arrays( @array );
print Dumper(\%hash);
sub hash_of_arrays {
die "Odd number of elements in hash (of arrays) assignment"
if @_ % 2;
# I never understood why this is a *warning* :-)
# populate hash by hand
my %hash;
while (@_) {
my $key = shift;
my $value = shift;
push @{ $hash{$key} }, $value;
# here hash values automatically become
# empty arrayrefs if not defined, thanks Larry
};
return %hash;
# *tecnically*, this one returns *array*
# and converts it back to hash
};
因为散列只能有唯一的键,所以不要将列表分配给散列,而是使用from进行处理 输出
$VAR1 = {
'tinku' => [
15,
18,
17,
16
],
'rita' => [
18,
19
],
'tina' => [
4
]
};
因为散列只能有唯一的键,所以不要将列表分配给散列,而是使用from进行处理 输出
$VAR1 = {
'tinku' => [
15,
18,
17,
16
],
'rita' => [
18,
19
],
'tina' => [
4
]
};
这里的其他响应中所涵盖的技术和模式都是经过实践检验的、真正的习惯用法,对于充分利用Perl、理解现有代码以及使用大量较旧的Perl编译器是必不可少的。只是为了好玩我想我还提到了一些其他方法:
perl-5.22
中有一个可读性很强的新语法,它可以替代。我要说一些更时髦的东西。Perl6还提供了一种很好的方法,可以将具有潜在非唯一键的键/值对列表转换为包含具有多个值的键的散列
正如其他回应所指出的,所有这些的“关键”是:
要使散列键引用多个值,这些值不仅需要是列表或数组,还需要是匿名数组[]
或引用
使用
perl-5.22提供的新语法
显示了标准的Perl习惯用法。正在使用0的遍历@names
$#名称
确保重叠键不会“丢失”,而是指向多个值的匿名数组。使用perl-5.22
我们可以使用List::Util
(核心模块)中的pairs()
函数,将键/值对添加到哈希中,并以稍微不同的方式解释重叠或重复的键:
use experimental qw(postderef);
use List::Util qw/pairs/;
my %hash;
my $a_ref = [ qw/tinku 15 tina 4 rita 18 tinku 18 tinku 17 tinku 16 rita 19/ ];
push $hash{$_->key}->@* , $_->value for pairs @$a_ref;
use DDP;
p %hash;
从1.39版开始,List::Util::pairs()
将数组引用作为可通过->key
和->value
方法访问的对象返回。该示例使用了LEONT的pragma,使内容更加紧凑
输出:
{
rita [
[0] 18,
[1] 19
],
tina [
[0] 4
],
tinku [
[0] 15,
[1] 18,
[2] 17,
[3] 16
]
}
{:rita(["18", "19"]), :tina("4"), :tinku(["15", "18", "17", "16"])}<>
至于哪一种更具“可读性”:很难击败容易“摸索”的标准方法,但通过最新版本的perl5中提供的新语法,我们可以探索新习语的潜力。我真的开始喜欢后缀解引用了。TIMTOWTDI和更远的地方
@宫川的
Hash::MultiValue
有了这个模块,您就可以创建一个Hash::MultiValue
对象(有许多方法以各种方式访问它)和一个简单的Hash引用,以方便地处理每个键的多个值
#!/usr/bin/env perl -l
use Hash::MultiValue;
use strict;
use warnings;
my $mvhash = Hash::MultiValue->new(tinku =>15, tina =>4, rita =>18,
tinku =>18, tinku =>17, tinku =>16, rita =>19);
print "\ntinku's values:\n", join " ", $mvhash->get_all('tinku');
print "\nflattened mvhash:\n", join " ", $mvhash->flatten ;
print "\n ... using mvhash as a hashref:" ;
print join " ", $mvhash->get_all($_) for keys %$mvhash ;
print "\n", '... as a "mixed" hashref with each():';
my $mvhash_ref = $mvhash->mixed ;
while ( my ($k, $v) = each $mvhash_ref ) {
print "$k => " , ref $v eq "ARRAY" ? "@{$v}" : "$v" ;
}
输出:
{
rita [
[0] 18,
[1] 19
],
tina [
[0] 4
],
tinku [
[0] 15,
[1] 18,
[2] 17,
[3] 16
]
}
{:rita(["18", "19"]), :tina("4"), :tinku(["15", "18", "17", "16"])}<>
tinku的价值观:
15 18 17 16
平铺mvhash:
tinku 15 tina 4 rita 18 tinku 18 tinku 17 tinku 16 rita 19
... 使用mvhash作为hashref:
15 18 17 16
18 19
4.
... 将hashref与each()混合使用:
tinku=>15 18 17 16
丽塔=>18 19
蒂娜=>4
一旦您的散列作为hash::MultiValue
对象可用,您就可以通过各种方式对其进行操作,以快速创建临时副本和散列引用。只需将它们分配到标量和Dump
the(或使用DDP
)即可了解其工作原理:
use DDP;
my $hmulti = $mvhash->multi; p $hmulti ;
my $hmixed = $mvhash->mixed; p $hmixed
对hash::multi-value
对象使用常规哈希操作有一些限制(像dd\$mvhash
这样的东西不会显示整个哈希-您需要执行dd$hash->multi
),但是在某些情况下,以这种方式使用多值哈希是有好处的(即,某些功能所需的可读性更强和/或代码可能更少)
您仍然需要识别何时/何地Hash::MultiValue
是有用的,因此它不是明确的“更容易”或“更干净”——但它是对perl工具的另一个有用的补充
Perl 6-仅供比较 Perl6对于从列表中获取键/值对来说更为紧凑,因为您可以使用,按元素组遍历列表,然后使用
push
将它们排列成散列。您可以通过“自动”解释重叠键的方式来执行此操作。参见此简短的Perl6片段:
my %h ;
for <tinku 15 tina 4 rita 18 tinku 18 tinku 17 tinku 16 rita 19> -> $k, $v {
%h.push($k => $v) ;
}
%h.perl.say ;
输出:
{
rita [
[0] 18,
[1] 19
],
tina [
[0] 4
],
tinku [
[0] 15,
[1] 18,
[2] 17,
[3] 16
]
}
{:rita(["18", "19"]), :tina("4"), :tinku(["15", "18", "17", "16"])}<>
{:rita([“18”、“19”),:tina(“4”),:tinku([“15”、“18”、“17”、“16”)}
比照
- 示例脚本
perl
编译器使编写perl-co成为可能