[英]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.