use Number::Range;
my $range = Number::Range->new();
$range->addrange(0,1,2,3,4,8,9,10,12,14,16,17,19);
my $range_list = join ', ', map join('-',@$_), $range->rangeList;
(rangeList 返回例如[0,4],[8,10],[12],[14],[16,17],[19])
还有 Set::IntSpan,它或多或少做同样的事情,只是具有重载、无限范围和其他附加功能。它这样做的方式有点麻烦:
use Set::IntSpan 'grep_spans';
my @array = (0, 1, 2, 3, 4, 8, 9, 10, 12, 14, 16, 17, 19);
my $set = Set::IntSpan->new(@array);
my @range_list;
grep_spans {
push @range_list, $_->[0] == $_->[1] ? $_->[0] : "$_->[0]-$_->[1]";
} $set;
my $range_list = join ', ', @range_list;
这是另一种方式:
my $range_list = List::Util::reduce { $a =~ /^\z/ ? "$b" : $a =~ /-(@{[$b-1]})\z/ ? ($a =~ s/$1\z/$b/, $a) : $a =~ /(?<![0-9])@{[$b-1]}\z/ ? "$a-$b" : "$a, $b" } '', 0,1,2,3,4,8,9,10,12,14,16,17,19;