开发者

Searching for indices of consecutive elements in an array

开发者 https://www.devze.com 2023-03-10 08:45 出处:网络
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.

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)


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.


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 ();
}
0

精彩评论

暂无评论...
验证码 换一张
取 消