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

如何在perl中将整数数组转换为区域?,perl,Perl,我现在有一个整数数组, (1,13,3,5,6,7,11,10,8,2,12) 我想从这个数组中得到连续的子区域, 上述数组的结果应为(1,3)、(5,8)、(10,13) 阵列可能非常大。有人有什么想法吗 非常感谢 您可以使用该模块: 产出: 如果一次运行只包含一个数字,则下限和上限将相同,例如[42,42] 演出 正如萨尔瓦在评论中指出的那样,在大量射程中表现不佳。另一种选择是,根据使用二进制搜索,并倾向于O log N性能。如果同时安装,您将获得更好的性能(无需更改use语句,如果安装了X

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

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

非常感谢

您可以使用该模块:

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

演出 正如萨尔瓦在评论中指出的那样,在大量射程中表现不佳。另一种选择是,根据使用二进制搜索,并倾向于O log N性能。如果同时安装,您将获得更好的性能(无需更改
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;
产出: 请注意,要对范围执行任何有用的操作,必须遍历此数组;在第一次遍历集合时执行此工作会更有效,而不是遍历两个不同的结构。

您可以使用以下模块:

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

演出 正如萨尔瓦在评论中指出的那样,在大量射程中表现不佳。另一种选择是,根据使用二进制搜索,并倾向于O log N性能。如果同时安装,您将获得更好的性能(无需更改
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;
产出:
请注意,要对范围执行任何有用的操作,必须遍历此数组;在第一次遍历集合时执行此工作会更有效,而不是遍历两个不同的结构。

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

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;

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

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;

如果你想用最少的努力快速地把工作做好,就按照他的建议去做

如果你想要一个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);

我没有尽力减少代码。它打印结果,而不是将其打包到数据结构中以供重用。它不会处理空数组。

如果您想以最小的努力快速完成工作,请按照his中的建议使用

如果你想要一个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);


我没有尽力减少代码。它打印结果,而不是将其打包到数据结构中以供重用。它不处理空数组。

为什么
5,8
而不是
5,6
?是否应首先对数字列表进行排序?@ССаа27:似乎应该对数字进行排序。您能否将
(1,13,3,5,6,7,11,10,8,2,12,15,1)
的预期结果作为有效的perl数据结构发布?[添加了“单个数字”范围和一个重复数字(1)]@AndrzejA.Filip应该是数组列表,(1,3)、(5,8)、(10,13)、(15)。单个数字应该保留,重复的数字只计算一次。为什么
5,8
而不是
5,6
?是否应首先对数字列表进行排序?@ССаа27:似乎应该对数字进行排序。您能否将
(1,13,3,5,6,7,11,10,8,2,12,15,1)
的预期结果作为有效的perl数据结构发布?[添加了“单个数字”范围和一个重复数字(1)]@AndrzejA.Filip应该是数组列表,(1,3)、(5,8)、(10,13)、(15)。单号必须保留,重复号只计算一次。很好!第一次看到这个模块。总是想知道人们是如何知道(记住)数千个模块的……我上周碰巧需要这个模块。请注意,
Set::IntSpan
在内部不使用任何类型的索引,因此当范围数量增加时(它是
O(N^2)
),性能会下降。嘿,但是你有了它,作者声称,线性搜索删除了吗?@salva很好,谢谢。我添加了一个
Set::IntSpan::Fast
解决方案。很好!第一次看到这个模块。总是想知道人们是如何知道(记住)数千个模块的……我上周碰巧需要这个模块。请注意,
Set::IntSpan
在内部不使用任何类型的索引,因此当范围数量增加时(它是
O(N^2)
),性能会下降。嘿,但是你有了它,作者声称,线性搜索删除了吗?@salva很好,谢谢。我添加了一个
Set::IntSpan::Fast
solution。这比Set::IntSpan更快不可编译。@jm666,还有Set::IntSpan::Fast和XS版本Set::IntSpan::Fast::XS,用于大数据集比我的方法更快。这比Set::IntSpan更快不可编译。@jm666,还有Set::IntSpan::Fast和XS版本Set::IntSpan::Fast::XS,它们对于大型数据集的速度比我的方法快。
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)