use*_*275 5 arrays perl extract sequence
我试图在整数数组中搜索一系列数字.例如,如果数组由数字组成1,2,3,10,12,14,则可以将其汇总为
1到3,偏移量为1,
偏移2为10到14
在我的代码下面,我从第二个元素循环遍历数组,跟踪连续数组元素之间的偏移量,如果偏移量发生变化,则创建一个新的"系列":
use strict;
use warnings;
my @numbers = (1,2,3,10,12,14); #array to extract series from 
my $last_diff;
my $start = $numbers[0];
my $end;
my @all_series; #array will hold all information on series
for my $i (1..($#numbers+1)){
        my $diff;
        if ($i <($#numbers+1)){
                $diff = $numbers[$i] - $numbers[$i-1];
        }
        if (!$diff || ( $last_diff && ($last_diff != $diff)) ) {
                $end = $numbers[$i-1];
                my $series = { 'start'=> $start,
                            'end'  => $end,
                            'offset'=> $start == $end ? 1 : $last_diff,
                };
                push @all_series, $series;
                $start = $numbers[$i];
        }
        $last_diff = $diff;
}
use Data::Dumper;
print Dumper(@all_series);
输出如下:
$VAR1 = {
          'offset' => 1,
          'end' => 3,
          'start' => 1
        };
$VAR2 = {
          'offset' => 1,
          'end' => 10,
          'start' => 10
        };
$VAR3 = {
          'offset' => 2,
          'end' => 14,
          'start' => 12
        };
这不是期望的结果,因为最后两个系列可以概括为一个(10到14,偏移2而不是两个系列).
算法中的缺陷与perl无关,但是,也许有人可以给我一个如何最好地处理这个问题的提示,也许存在一些perl特定的技巧.
在我的应用程序中,数组中的所有整数都按升序排列,并且不存在重复的数字.
编辑 如果单个数字出现不能认真对待严重,则它们应该是一系列长度的数字.
可以将更多的数字汇总到系列,越好(我想最小化系列的数量!)
问题出在三元运算符上。如果你使用普通的
offset => $last_diff,
你会注意到有
$VAR2 = {
          'offset' => 7,
          'end' => 10,
          'start' => 10
这在某种程度上是正确的。为了避免这种情况,您可以undef $diff在推送到@series后进行。它会为您的情况产生预期的输出,但仍会视为1 2 3 7 10 12 14三个序列,从 1、7 和 12 开始。现在您需要的是以某种方式使更长的句子变得贪婪。
我尝试了以下内容,但您应该进行更多测试:
#!/usr/bin/perl
use warnings;
use strict;
use Data::Dumper;
my @numbers = (1, 2, 3, 10, 12, 14);
my $last_diff;
my $start = $numbers[0];
my @all_series;
for my $i (1 .. $#numbers + 1) {
    my $diff;
    if ($i < $#numbers + 1) {
        $diff = $numbers[$i] - $numbers[ $i - 1 ];
    }
    # Merge with the last number from the previous series if needed:
    if (!$last_diff # Just starting a new series.
        and $i > 2  # Far enough to have preceding numbers.
        and $diff and $diff == $numbers[ $i - 1 ] - $numbers[ $i - 2 ]
       ) {
        $all_series[-1]{end} = $numbers[ $i - 3 ];
        $all_series[-1]{offset} = 0 if $all_series[-1]{start} == $all_series[-1]{end};
        $start = $numbers[ $i - 2 ];
    }
    if (! $diff or ( $last_diff && ($last_diff != $diff)) ) {
        push @all_series, { start  => $start,
                            end    => $numbers[ $i - 1 ],
                            offset => $last_diff,
                          };
        $start = $numbers[$i];
        undef $diff;
    }
    $last_diff = $diff;
}
print Dumper(@all_series);