Perl:查找数组

时间:2017-08-29 20:42:36

标签: perl sorting integer range

在Perl中,如果我有一个排序的整数数组,是否有一种简洁的方法将其转换为整数的范围的列表或数组?

E.g。假设我有:

my @numbers=(3,4,5,6,9,10,12,14,15,16,17);

我想确定存在的数字范围是:

3-6,9-10,12,14-17

我知道我可以通过For循环检查来查看我们是否已经达到了两个数组元素之间的差距等等。但在我这样做之前,我想我会看看是否有一些紧凑的符号或核心功能,可以实现这一目标。

我不想加载任何非核心库。我使用的是Cygwin Perl 5.22。

感谢。

3 个答案:

答案 0 :(得分:6)

my @ranges;
for (@numbers) {
   if (@ranges && $_ == $ranges[-1][1]+1) {
      ++$ranges[-1][1];
   } else {
      push @ranges, [ $_, $_ ];
   }
}

say join ',', map { $_->[0] == $_->[1] ? $_->[0] : "$_->[0]-$_->[1]" } @ranges;

答案 1 :(得分:1)

#!/usr/bin/env perl

use strict;
use warnings;

use autouse 'YAML::XS' => 'Dump';

use Const::Fast;
use Graph::Undirected;
use List::Util qw( min max shuffle );
use Test::More;

const my %I => (in => 0, out => 1);

my @cases = (
    [[shuffle 3 .. 6, 9 .. 12, 14 .. 17] => [[3, 6], [9, 12], [14, 17]]],
    [[shuffle 3 .. 6, 9 .. 12, 14 .. 17, 21] => [[3, 6], [9, 12], [14, 17], [21]]],
);

for my $case ( @cases ) {
    is_deeply(
        spans($case->[$I{in}]),
        $case->[$I{out}],
        Dump($case->[$I{in}]) . ' = ' . Dump($case->[$I{out}])
    );
}

done_testing;

sub spans {
    my $sequence = shift;
    my $g = Graph::Undirected->new;

    $g->add_vertex($_) for @$sequence;
    $g->has_vertex($_ + 1) and $g->add_edge($_, $_ + 1) for @$sequence;

    return [
        sort { $a->[0] <=> $b->[0] }
        map $_->[0] == $_->[1] ? [ $_->[0] ] : $_,
        map [min(@$_), max(@$_)],
        $g->connected_components
    ];
}

输出:

$ prove -v spans.pl 
ok 1 - ---
# - 9
# - 4
# - 10
# - 14
# - 6
# - 5
# - 3
# - 15
# - 12
# - 17
# - 11
# - 16
#  = ---
# - - 3
#   - 6
# - - 9
#   - 12
# - - 14
#   - 17
# 
ok 2 - ---
# - 17
# - 16
# - 12
# - 11
# - 6
# - 9
# - 10
# - 5
# - 3
# - 4
# - 21
# - 14
# - 15
#  = ---
# - - 3
#   - 6
# - - 9
#   - 12
# - - 14
#   - 17
# - - 21
# 
1..2
ok
All tests successful.
Files=1, Tests=2,  1 wallclock secs ( 0.04 usr  0.01 sys +  0.25 cusr  0.02 csys =  0.32 CPU)
Result: PASS

答案 2 :(得分:-1)

好的,在搞乱了几分钟之后,以下似乎在我试过的几个快速测试集上运行得相当好。如果有人对这种方法有任何想法,我会很感激。

use strict;
use warnings;
my @numbers=(-7,-3,-2,-1,3,4,5,6,9,10,12,14,15,16,17);

my @ranges=();
my $start;
$start=$numbers[0];
for(my $i=0; $i<@numbers; $i++){
    if($numbers[$i]>$numbers[$i-1]+1){

        push @ranges, ($start == $numbers[$i-1] ? $start : $start.":".$numbers[$i-1]);
        $start=$numbers[$i];
        print "New start: ".$numbers[$i]."\n";
    }
}
push @ranges, ($start == $numbers[@numbers-1] ? $start : $start.":".$numbers[@numbers-1]);

print join(",",@ranges)."\n";