如果你可以use Text::CSV_XS as Shawn shows,那就去做吧。
我们在Intermediate Perl 中有一个练习可以做到这一点。使用第一行将标头名称映射到位置,然后使用该散列转换另一种方式。这里大量使用postfix dereferencing:
use v5.24;
my $data = [
[ 'id', 'name', 'value' ],
[ 23, 'foo', 77 ],
[ 44, 'bar', 'dfd' ],
];
# ikegami's suggestion
my %name_to_index = map { $data->[0][$i] => $_ } 0..$data->[0]->$#*;
foreach my $i ( 1 .. $data->$#* ) {
say $data->[$i][ $name_to_index{name} ]
}
这是适用于 v5.24 之前的版本的circumfix 版本,但我认为它更丑(而且你必须使用一个六岁的、不受支持的 Perl):
use v5.10;
my $data = [
[ 'id', 'name', 'value' ],
[ 23, 'foo', 77 ],
[ 44, 'bar', 'dfd' ],
];
# ikegami's suggestion
my %name_to_index = map { $data->[0][$i] => $_ } 0.. $#{ $data->[0] };
foreach my $i ( 1 .. $#{ $data } ) {
say $data->[$i][ $name_to_index{name} ]
}
由于真正的代码可能要复杂得多,我认为当您不深入研究所有数据结构时,通常会更容易理解。如果您不介意额外的工作(就像您在热循环中所做的那样),您可以将您的行变成一个哈希,其中键是标题(类似于 Text::CSV_XS 所做的)然后使用该哈希而不考虑整个取消引用链。此示例使用哈希切片一次填充所有内容。之后你玩%hash而不是$data->[$i][...]:
use v5.24;
my $data = [
[ 'id', 'name', 'value' ],
[ 23, 'foo', 77 ],
[ 44, 'bar', 'dfd' ],
];
my @headers = $data->[0]->@*;
foreach my $i ( 1 .. $data->$#* ) {
my %hash;
@hash{ @headers } = $data->[$i]->@*;
say $hash{name};
}
奇怪的是,在Pseudohash section in perlref 之后,文档显示了一个带有函数模板的示例。您可以定义子例程,而不是进行映射的哈希。有些人喜欢标头索引的名称看起来更干净一些,但我认为这不值得额外解释软refs违规和类型globs的解释:
use v5.24;
my $data = [
[ 'id', 'name', 'value' ],
[ 23, 'foo', 77 ],
[ 44, 'bar', 'dfd' ],
];
foreach my $name ( $data->[0]->@* ) {
state $n = 0;
my $m = $n++; # don't reference $n
no strict 'refs'; # Hey there!
*{uc $name} = sub () { $m }; # runtime sub definition
}
foreach my $i ( 1 .. $data->$#* ) {
say $data->[$i][ NAME() ]
}