簡體   English   中英

Perl:查找數組中數字的范圍

[英]Perl: Find ranges of numbers in an array

在Perl中,如果我有一個排序的整數數組,是否有一種緊湊的方法可以將其轉換為整數范圍的列表或數組?

例如,假設我有:

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。

謝謝。

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;
#!/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

好吧,在處理了幾分鍾之后,以下內容在我嘗試的一些快速測試集上似乎工作得很好。 如果有人對此方法有任何想法,我將不勝感激。

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";

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM