如何将整数数组转换为perl中的区域?

时间:2014-07-28 14:04:38

标签: perl

我现在有一个整数数组,如, (1,13,3,5,6,7,11,10,8,2,12) 我想让连续的子区域形成这个数组, 上述数组的结果应为(1,3),(5,8),(10,13)

阵列可能非常大。有人有什么想法吗?

非常感谢。

3 个答案:

答案 0 :(得分:5)

您可以使用Set::IntSpan模块:

use strict;
use warnings;

use Data::Dump;
use Set::IntSpan;

my @values = (1, 13, 3, 5, 6, 7, 11, 10, 8, 2, 12);
my $set = Set::IntSpan->new(@values);
my @spans = $set->spans;

dd @spans;

输出:

([1, 3], [5, 8], [10, 13])

如果一个运行只包含一个数字,则下限和上限将相同,例如[42, 42]

效果

正如salva在评论中指出的那样,Set::IntSpan在大量范围内表现不佳。另一种选择是Set::IntSpan::Fast,根据documentation,它使用二进制搜索并趋向于O log N性能。如果您同时安装Set::IntSpan::Fast::XS,您将获得更好的性能(无需更改use声明,如果已安装XS版本,则会自动使用。)

以下内容遍历范围并将它们推送到数组:

use strict;
use warnings;

use Data::Dump;
use Set::IntSpan::Fast;

my @values = (1, 13, 3, 5, 6, 7, 11, 10, 8, 2, 12);
my $set = Set::IntSpan::Fast->new;
$set->add(@values);

my @ranges;
my $iter = $set->iterate_runs;
while (my ($from, $to) = $iter->()) {
    push @ranges, [ $from, $to ];
}

dd @ranges;

输出:

([1, 3], [5, 8], [10, 13])

请注意,要对范围执行任何有用的操作,您必须遍历此数组;在第一次迭代集合而不是遍历两个不同的结构时,完成工作会更有效。

答案 1 :(得分:3)

使用散列,获取一些随机元素并查找前后的连续元素:

my @ints = (...);
my %ints = map { $_ => 1 } @ints;
my @ranges;
while (keys %ints) {
  my $bottom = my $top = each %ints;
  delete $ints{$bottom};
  1 while (delete $ints{--$bottom});
  1 while (delete $ints{++$top});
  push @ranges, [$bottom + 1, $top - 1];
}
say join ', ', map "$_->[0]-$_->[1]", @ranges;

答案 2 :(得分:1)

如果您想以最小的努力快速完成工作,请在Set::IntSpan中使用ThisSuitIsBlackNot作为answer建议。

如果您想要DIY工作,那么您可以考虑使用此代码作为基础:

#!/usr/bin/env perl
use strict;
use warnings;

$, = " ";

my @data = (1, 13, 3, 5, 6, 7, 11, 10, 8, 2, 12);

sub pr_region
{
    my($lo, $hi) = @_;
    print "($lo";
    print ", $hi" if ($lo != $hi);
    print ")\n";
}

sub print_regions
{
    my(@data) = @_;
    print "Raw: ", @data, "\n";

    my @sorted = sort { $a <=> $b } @data;
    #print "Sorted: ", @sorted, "\n";

    my $lo = $sorted[0];
    for my $i (1 .. scalar(@sorted)-1)
    {
        if ($sorted[$i-1] != $sorted[$i] - 1 &&
            $sorted[$i-1] != $sorted[$i])
        {
            pr_region($lo, $sorted[$i-1]);
            $lo = $sorted[$i];
        }
    }
    pr_region($lo, $sorted[$#sorted]);
}

print_regions(@data);
print_regions(1);
print_regions(1, 10);
print_regions(1, 2, 10);
print_regions(1, 9, 10);
print_regions(@data, 11, 3, 19, -3);

它的输出是:

Raw:  1 13 3 5 6 7 11 10 8 2 12 
(1, 3)
(5, 8)
(10, 13)
Raw:  1 
(1)
Raw:  1 10 
(1)
(10)
Raw:  1 2 10 
(1, 2)
(10)
Raw:  1 9 10 
(1)
(9, 10)
Raw:  1 13 3 5 6 7 11 10 8 2 12 11 3 19 -3 
(-3)
(1, 3)
(5, 8)
(10, 13)
(19)

我没有尽力减少代码。它打印结果而不是将它们打包在数据结构中以便重复使用。它没有处理空数组。