所以我有一个数组my @a = (a,b,c,d,e,f)
另一个数组my @b = (c,d,e)
我想查找@a
中是否有三个与@b
中的元素匹配的连续元素。
然后,如果有,我想得到这些元素存在的索引。
所以在上面的例子中我想得到一个像(2,3,4)
这样的数组。
另一个例子:
my @a = (1,2,3,4,5)
my @b = (2,3)
输出:(1,2)
答案 0 :(得分:4)
一种天真的方法:
@A = 1..5;
@B = 2..3;
A_LOOP:
for my $a_index (0..$#A) {
for my $b_index (0..$#B) {
next A_LOOP unless $A[$a_index+$b_index] eq $B[$b_index];
}
@results = map $a_index+$_, 0..$#B;
last;
}
如果这还不够快(根据您的示例,不太可能),Boyer-Moore并不难实现。
答案 1 :(得分:2)
这是一般解决方案。这使用了List :: MoreUtils中的'all'函数来减少与true / false结果的比较,这简化了逻辑。
我把它放到一个sub的形式,你传递对任何两个数组的引用。传递给函数的第一个数组ref应该是超集,第二个数组ref应该引用子集数组。
我喜欢这个解决方案的是它可以应用于任何两个简单的数组(例如,它不限于寻找一个双元素子集)。我确实选择了元素(eq)的字符串比较而不是数字(==)。这样,如果你有非数字元素,它就有效。但是,它会将'00'和'0'评估为不相等(因为它们不是相同的字符串)。如果您喜欢数字比较,只需找到'eq'并将其更改为'=='。
以下是代码:
use 5.010_001;
use strict;
use warnings;
use List::MoreUtils qw/all/;
my @array_a = qw/1 2 3 4 5/;
my @array_b = qw/2 3/;
{
local $, = " ";
my( @results ) = find_group( \@array_a, \@array_b );
say "Success at ", @results if @results;
}
sub find_group {
my( $array_1, $array_2 ) = @_;
foreach my $array_1_idx ( 0 .. $#{$array_1} ) {
my $moving_idx = $array_1_idx;
return $array_1_idx .. ( $moving_idx - 1 ) if
all { $_ eq $array_1->[$moving_idx++] } @{$array_2};
}
return ();
}