问题 - 我有两个数组如下。
my @arr1 = qw( jon won don pon );
my @arr2 = qw( son kon bon won kon don pon won pon don won);
我需要从@ arr2中删除@ arr1的第一个匹配元素,即在上面的示例中,我需要从@ arr2中删除won。
目前我的逻辑如下。
#!/usr/bin/perl
my @arr1 = qw( jon won don pon );
my @arr2 = qw( son kon bon won kon don pon won pon don won);
my @remove_indices = ();
my $remove_element;
my $first_remove_index;
OUTER_FOR: for my $i (0..@arr2) {
$outer_element = $arr2[$i];
foreach my $innr_element ( @arr1 ) {
if($innr_element eq $outer_element) {
push(@remove_indices, $i);
$first_remove_index = $i;
$remove_element = $innr_element;
last OUTER_FOR;
}
}
}
for my $i ($first_remove_index+1..@arr2) {
$outer_element = $arr2[$i];
if($remove_element eq $outer_element) {
push(@remove_indices, $i);
}
}
if (@remove_indices > 0) {
map {splice (@arr2, $_, 1)} reverse(@remove_indices);
}
print "@arr2";
但它似乎是典型的C / C ++风格逻辑。我不能使用哈希。有没有perl方法做同样的事情?
答案 0 :(得分:1)
这是另一种方式(假设您要删除所有出现的第一个匹配元素):
use strict;
use warnings;
my @arr1 = qw(jon won don pon);
my @arr2 = qw(son kon bon won kon don pon won pon don won);
for my $elem (@arr2){
if(grep { $_ eq $elem } @arr1){
@arr2 = grep { $_ ne $elem } @arr2;
last;
}
}
print "@arr2";
输出:
son kon bon kon don pon pon don
答案 1 :(得分:1)
病毒,当然你可以使用哈希来解决这个问题。
如果扩展了示例中一个或两个数组的大小,它实际上会为您提供更好的CPU使用率。
use strict;
my @arr1 = qw(jon won don pon);
my @arr2 = qw(son kon bon won kon don pon won pon don won);
my $i;
my %h;
for (@arr2) { push @{$h{$_} }, $i++ }
for my $a (@arr1) {
if (exists $h{$a}) {
for (@{$h{$a}}) {
$arr2[$_] = '';
}
last;
}
}
@arr2 = grep { length } @arr2;
print "@arr2\n";
我很好奇不同提出的解决方案的相对效率,并编写了一个测试程序来试用它们。您会很高兴地知道您的程序在使用测试数据时非常好。但是当数组的大小开始增长时就不行了!
下面的内容有点疯狂,我知道,但无论如何都要进行。但是,如果您每天要运行数百万次应用程序,那么通过对硬件进行基准测试可能会让您受益匪浅。所以忍受我:)。
以下是5个解决方案中每个解决方案按上面发布顺序的相对CPU时间(最经济的显示为“1”)。第一个结果列使用示例中使用的数据保存CPU时间,并且后面的三列通过在前面添加50个元素来增加两个数组中的一个或两个,其中的内容在另一个中找不到。
First array @arr1 @arr1 @arr1+50 @arr1+50
Second array @arr2 @arr2+50 @arr2 @arr2+50
Your program 1 7 3 45
Grep approach 1 1 6 3 43
Grep approach 2 3 9 33 160
Convert to string 2 4 3 6
Using hash 2 6 2 7
在测试数据上运行时,哈希解决方案的CPU密集度是您的两倍。但是如果你将第二个数组扩展50个元素,那么散列会更好一点,因为你的CPU时间现在已经增加到7而散列方法已经从2变为6.但如果两个数组都更大,你的程序需要45倍以上CPU完成时间比原始数据需要的时间长,而哈希程序只需要3.5倍(从2到7)。
显然所有都需要更多的CPU时间,因为阵列的大小增长但不是相同的比例,并且它们的减速也不是线性的。它们都可能都被调整了一下,我想结果会在不同的硬件平台上发生变化,但这些应该合理地表明它们的相对效率。以下是原始数组增长100个元素而不是50个元素的时间。
First array @arr1 @arr1 @arr1+100 @arr1+100
Second array @arr2 @arr2+100 @arr2 @arr2+100
Your program 1 12 5 173
Grep approach 1 1 12 4 162
Grep approach 2 3 16 68 612
Convert to string 2 7 5 12
Using hash 2 11 3 12
因此,对于是否应该更喜欢第4种方法(将测试数组转换为单个字符串然后通过它进行正则表达式,一种死于羊毛的perl程序员的解决方案)和第5种方法,这是一个折腾的问题。它使用哈希)。从边缘来看,“转换为字符串”方法更好,这对许多程序员来说都是违反直觉的。它也简短易读。
底线...如果您将使用类似示例中的数据集,那么您的代码就可以了(尽管您应该在INNER_LOOP修复“(0 .. @ arr2)”:读取“(0) .. $#ARR2)“)。
否则,根据您的口味使用第4或第5。我个人会选择不是我的,“转换为字符串”程序,只要我100%确定加入的字符不会出现在数据中。
我想我现在最好回去做一些有效的事情:)
答案 2 :(得分:0)
您可以使用简单的for
循环,并在找到匹配项时使用last
退出循环。使用grep
删除关键字。
use strict;
use warnings;
my @arr1 = qw( jon won don pon );
my @arr2 = qw( son kon bon won kon don pon won pon don won);
my @out;
for my $word (@arr1) {
my @new = grep !/^\Q$word\E$/, @arr2;
if (@new != @arr2) {
print "'$word' found\n";
@out = @new;
last;
}
}
print "@out";
请注意,我使用\Q ...\E
来禁用可能的正则表达式元字符。 !=
比较会将数组大小相互比较,当找到差异时,我们知道我们找到了匹配。
答案 3 :(得分:0)
我确信有很多方法可以做到这一点。这是一个...
my @arr1 = qw( jon won don pon );
my @arr2 = qw( son kon bon won kon don pon won pon don won);
my $s2 = join '|', @arr2;
my $item;
foreach $item (@arr1) {
last unless $s2 !~ s/$item//g;
}
$s2 =~ s/\|\|/\|/g;
@arr2 = split /\|/, $s2;
print Dumper( @arr2 );