Perl:删除数组项并调整数组大小
Perl: Removing array items and resizing the array
我正在尝试使用 Perl 中的另一个数组来过滤一组术语。我在 OS X 上安装了 Perl 5.18.2,尽管我 use 5.010
的行为是一样的。这是我的基本设置:
#!/usr/bin/perl
#use strict;
my @terms = ('alpha','beta test','gamma','delta quadrant','epsilon',
'zeta','eta','theta chi','one iota','kappa');
my @filters = ('beta','gamma','epsilon','iota');
foreach $filter (@filters) {
for my $ind (0 .. $#terms) {
if (grep { /$filter/ } $terms[$ind]) {
splice @terms,$ind,1;
}
}
}
这可以提取与各种搜索词匹配的行,但数组长度不会改变。如果我写出结果 @terms
数组,我得到:
[alpha]
[delta quadrant]
[zeta]
[eta]
[theta chi]
[kappa]
[]
[]
[]
[]
如您所料,打印 scalar(@terms)
得到的结果是 10
。
我想要的是长度为 6 的结果数组,末尾没有四个空白项。我如何获得该结果?考虑到 perldoc page about splice
说“数组根据需要增长或收缩”,为什么数组没有收缩?
(我的 Perl 不是很流利,所以如果你在想“你为什么不……?”,那几乎可以肯定是因为我不知道或不明白当我听说它的时候。)
您可以随时重新生成数组,减去您不想要的东西。 grep
充当过滤器,让您决定需要哪些元素,不需要哪些元素:
#!/usr/bin/perl
use strict;
my @terms = ('alpha','beta test','gamma','delta quadrant','epsilon',
'zeta','eta','theta chi','one iota','kappa');
my @filters = ('beta','gamma','epsilon','iota');
my %filter_exclusion = map { $_ => 1 } @filters;
my @filtered = grep { !$filter_exclusion{$_} } @terms;
print join(',', @filtered) . "\n";
如果你手头有一个像%filter_exclusion
这样的简单结构,这就很容易了。
更新:如果要允许任意子字符串匹配:
my $filter_exclusion = join '|', map quotemeta, @filters;
my @filtered = grep { !/$filter_exclusion/ } @terms;
要查看发生了什么,请在每个步骤中打印数组的内容:当您拼接数组时,它会缩小,但您的循环迭代了 0 .. $#terms,因此在循环结束时, $ind 将指向数组末尾的后面。当您使用 grep { ... } $array[ $too_large ]
时,Perl 需要在 grep 块内将不存在的元素别名为 $_
,因此它会在数组中创建一个 undef
元素。
#!/usr/bin/perl
use warnings;
use strict;
use feature qw{ say };
my @terms = ('alpha', 'beta test', 'gamma', 'delta quadrant', 'epsilon',
'zeta', 'eta', 'theta chi', 'one iota', 'kappa');
my @filters = qw( beta gamma epsilon iota );
for my $filter (@filters) {
say $filter;
for my $ind (0 .. $#terms) {
if (grep { do {
no warnings 'uninitialized';
/$filter/
} } $terms[$ind]
) {
splice @terms, $ind, 1;
}
say "\t$ind\t", join ' ', map $_ || '-', @terms;
}
}
如果您使用 $terms[$ind] =~ /$filter/
而不是 grep
,您仍然会收到未初始化的警告,但由于不需要为元素添加别名,因此不会创建它。
我正在尝试使用 Perl 中的另一个数组来过滤一组术语。我在 OS X 上安装了 Perl 5.18.2,尽管我 use 5.010
的行为是一样的。这是我的基本设置:
#!/usr/bin/perl
#use strict;
my @terms = ('alpha','beta test','gamma','delta quadrant','epsilon',
'zeta','eta','theta chi','one iota','kappa');
my @filters = ('beta','gamma','epsilon','iota');
foreach $filter (@filters) {
for my $ind (0 .. $#terms) {
if (grep { /$filter/ } $terms[$ind]) {
splice @terms,$ind,1;
}
}
}
这可以提取与各种搜索词匹配的行,但数组长度不会改变。如果我写出结果 @terms
数组,我得到:
[alpha]
[delta quadrant]
[zeta]
[eta]
[theta chi]
[kappa]
[]
[]
[]
[]
如您所料,打印 scalar(@terms)
得到的结果是 10
。
我想要的是长度为 6 的结果数组,末尾没有四个空白项。我如何获得该结果?考虑到 perldoc page about splice
说“数组根据需要增长或收缩”,为什么数组没有收缩?
(我的 Perl 不是很流利,所以如果你在想“你为什么不……?”,那几乎可以肯定是因为我不知道或不明白当我听说它的时候。)
您可以随时重新生成数组,减去您不想要的东西。 grep
充当过滤器,让您决定需要哪些元素,不需要哪些元素:
#!/usr/bin/perl
use strict;
my @terms = ('alpha','beta test','gamma','delta quadrant','epsilon',
'zeta','eta','theta chi','one iota','kappa');
my @filters = ('beta','gamma','epsilon','iota');
my %filter_exclusion = map { $_ => 1 } @filters;
my @filtered = grep { !$filter_exclusion{$_} } @terms;
print join(',', @filtered) . "\n";
如果你手头有一个像%filter_exclusion
这样的简单结构,这就很容易了。
更新:如果要允许任意子字符串匹配:
my $filter_exclusion = join '|', map quotemeta, @filters;
my @filtered = grep { !/$filter_exclusion/ } @terms;
要查看发生了什么,请在每个步骤中打印数组的内容:当您拼接数组时,它会缩小,但您的循环迭代了 0 .. $#terms,因此在循环结束时, $ind 将指向数组末尾的后面。当您使用 grep { ... } $array[ $too_large ]
时,Perl 需要在 grep 块内将不存在的元素别名为 $_
,因此它会在数组中创建一个 undef
元素。
#!/usr/bin/perl
use warnings;
use strict;
use feature qw{ say };
my @terms = ('alpha', 'beta test', 'gamma', 'delta quadrant', 'epsilon',
'zeta', 'eta', 'theta chi', 'one iota', 'kappa');
my @filters = qw( beta gamma epsilon iota );
for my $filter (@filters) {
say $filter;
for my $ind (0 .. $#terms) {
if (grep { do {
no warnings 'uninitialized';
/$filter/
} } $terms[$ind]
) {
splice @terms, $ind, 1;
}
say "\t$ind\t", join ' ', map $_ || '-', @terms;
}
}
如果您使用 $terms[$ind] =~ /$filter/
而不是 grep
,您仍然会收到未初始化的警告,但由于不需要为元素添加别名,因此不会创建它。