Perl内置函数能否查找数组中精确顺序匹配的子数组?
Perl 有序子数组匹配方案说明
Perl 核心没有提供单步完成「有序精确子数组匹配+批量返回起始索引+移除匹配段」全套操作的专用内置函数,但依托原生数组操作能力,无需安装任何第三方模块,即可实现完全符合需求的逻辑,支持数字、字符串等任意可做相等判断的元素类型。
核心实现代码
use strict; use warnings; # 查找所有有序精确匹配的子数组起始索引,默认支持重叠匹配 sub find_subarray_indices { my ($main_arr, $sub_arr) = @_; my @match_indices; my $main_len = @$main_arr; my $sub_len = @$sub_arr; return @match_indices if $sub_len > $main_len || $sub_len == 0; for my $start (0 .. $main_len - $sub_len) { my $match_flag = 1; for my $offset (0 .. $sub_len - 1) { # 比对逻辑可按需调整:数值类型可将ne替换为!=,引用/对象可自定义相等判断规则 if ($main_arr->[$start + $offset] ne $sub_arr->[$offset]) { $match_flag = 0; last; } } push @match_indices, $start if $match_flag; } return @match_indices; } # 从左到右非重叠移除所有匹配的子数组,返回处理后的新数组,不修改传入的原数组 sub remove_matched_subarrays { my ($main_arr, $sub_arr) = @_; my $main_len = @$main_arr; my $sub_len = @$sub_arr; return @$main_arr if $sub_len > $main_len || $sub_len == 0; my @keep_mark = (1) x $main_len; my $i = 0; while ($i <= $main_len - $sub_len) { my $match_flag = 1; for my $offset (0 .. $sub_len - 1) { if ($main_arr->[$i + $offset] ne $sub_arr->[$offset]) { $match_flag = 0; last; } } if ($match_flag) { # 匹配到就标记整段删除,跳过整段长度继续向后检索 @keep_mark[$i .. $i + $sub_len - 1] = (0) x $sub_len; $i += $sub_len; } else { $i += 1; } } my @result; for my $idx (0 .. $main_len - 1) { push @result, $main_arr->[$idx] if $keep_mark[$idx]; } return @result; }
示例验证结果
- 示例1:主数组
(1,2,3,4,5,6,7,8,9)、子数组(2,3,4),调用find_subarray_indices返回匹配起始索引(1),符合预期。 - 示例2:主数组
(4,2,3,4,2,3,4)、子数组(2,3,4),返回匹配索引(1,4),可正常识别重复出现的匹配段。 - 示例3:主数组
(2,3,2,3,2,2,3,2)、子数组(2,3,2),调用查找函数返回索引(0,2,5),和需求要求完全一致;调用移除函数后返回剩余数组(3,2),匹配示例给出的结果。
适配说明
- 如果查找时不需要支持重叠匹配(即匹配到一个子数组后,跳过整个匹配段长度再向后检索),只需要在查找函数匹配成功后,手动将
$start累加$sub_len - 1即可。 - 如果数组元素为引用、自定义对象等复杂类型,可替换代码中的标量比对逻辑,比如用
Scalar::Util的refaddr做引用地址比对,或传入自定义相等判断回调即可。 - 如果移除时需要删除所有匹配覆盖的位置(包括重叠区域),可调整移除逻辑为基于全量匹配索引标记删除位实现。
内容的提问来源于stack exchange,提问作者twSoulz
相关产品推荐
相关产品推荐

