搜索数组中连续元素的索引

发布于 2024-11-14 02:27:36 字数 340 浏览 7 评论 0原文

所以我有一个数组my @a = (a,b,c,d,e,f)
另一个数组 my @b = (c,d,e)

我想查找 @a 中是否有三个连续元素与 @b 中的元素匹配。 然后,如果有,我想获取这些元素所在的索引。

因此,在上面的情况下,我想获取一个数组,例如 (2,3,4)

另一个例子:
我的@a = (1,2,3,4,5)
my @b = (2,3)

输出:(1,2)

So I have an array my @a = (a,b,c,d,e,f)
And another array my @b = (c,d,e)

I want to find if there are three consecutive elements in @a that match those in @b.
Then, if there are, I want to get the indices those elements live in.

So in the case above I want to get an array such as (2,3,4).

Another example:
my @a = (1,2,3,4,5)
my @b = (2,3)

Output: (1,2)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

书信已泛黄 2024-11-21 02:27:36

一种幼稚的方法:

@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 实施起来并不困难。

A naive approach:

@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;
}

If this isn't fast enough (unlikely, given your examples), Boyer-Moore isn't that difficult to implement.

葬花如无物 2024-11-21 02:27:36

这是一个通用的解决方案。这使用 List::MoreUtils 中的“all”函数来减少与真/假结果的比较,从而稍微简化了逻辑。

我将其放入子形式中,您可以向其中传递对任意两个数组的引用。传递给函数的第一个数组 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 ();
}

Here is a general solution. This uses the 'all' function, from List::MoreUtils to reduce the comparison to a true/false result, which simplifies the logic a little.

I put it into the form of a sub to which you pass a reference to any two arrays. The first array ref passed to the function should be the superset, and the second array ref should refer to the subset array.

What I like about this solution is that it can apply to any two simple arrays (it isn't constrained to seeking a two-element subset, for example). I did choose a string comparison of the elements (eq) as opposed to numeric (==). That way it works if you have non-numeric elements. However, it will evaluate '00' and '0' as non-equal (because they're not the same string). If you favor a numeric comparison, just find the 'eq' and change it to '=='.

Here's the code:

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 ();
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文