Используя Set :: IntSpan :
use Set::IntSpan;
my @starts = (100,100,200,300,400,500,525);
my @ends = (150,125,250,350,450,550,550);
my (@uniq_starts, @unique_ends);
for my $s (Set::IntSpan->new([map [$starts[$_], $ends[$_]], 0 .. $#starts])->spans) {
push @uniq_starts, $s->[0];
push @uniq_ends, $s->[1];
}
print join(",", @uniq_starts), "\n";
print join(",", @uniq_ends), "\n";
Или решение бедного человека:
sub spans {
my @s = sort {$a->[0] <=> $b->[0] or $a->[1] <=> $b->[1]} @_;
my @res;
while (@s > 1) {
if ($s[0][1] >= $s[1][0]) {
splice @s, 0, 2, [$s[0][0], $s[1][1]];
} else {
push @res, shift @s;
}
}
push @res, @s;
return @res;
}
my @starts = (100,100,200,300,400,500,525);
my @ends = (150,125,250,350,450,550,550);
my (@uniq_starts, @unique_ends);
for my $s (spans(map [$starts[$_], $ends[$_]], 0 .. $#starts)) {
push @uniq_starts, $s->[0];
push @uniq_ends, $s->[1];
}
print join(",", @uniq_starts), "\n";
print join(",", @uniq_ends), "\n";
Вы можете проверить, что оно работает безупречно.
Более функциональный spans
версия:
sub spans {
return spans_(sort {$a->[0] <=> $b->[0] or $a->[1] <=> $b->[1]} @_);
}
sub spans_ {
if (@_ > 1 and $_[0][1] >= $_[1][0]) {
splice @_, 0, 2, [$_[0][0], $_[1][1]];
goto &spans_;
} elsif (@_) {
return shift, spans_(@_);
} else {
return;
}
}
PS: Если кто-то думает, что Perl является лаконичным языком, сравните ту же функцию алгоритма spans
в erlang.Я даже не знаю, как это будет выглядеть в APL или J:
spans(L) -> spans_(lists:sort(L)).
spans_([{A, B}, {C, D}|T]) when B >= C ->
spans_([{A, D}|T]);
spans_([H|T]) -> [H|spans_(T)];
spans_([]) -> [].