如何按起始坐标按数字顺序对两个坐标数组进行排序,例如
my @starts = (100,100,200,300,400,500,525);
my @ends = (150,125,250,350,450,550,550);
但如果在开始或结束列表中有两个匹配,请选择最大的区别? E.g。
my @uniq_starts = (100,200,300,400,500);
my @unique_ends = (150,250,350,450,550);
任何帮助都非常感谢!
另外,如果列表是这样的呢?
my @starts = (100,125,200,300,400,500,525);
my @ends = (150,175,250,350,450,550,550);
这会给我以下值:
-25, 25, 50, 50, 50, -25
我需要以下输出:
my @uniq_starts = (100,200,300,400,500);
my @unique_ends = (175,250,350,450,550);
所以我的价值观是:
25, 50, 50, 50
我可以通过删除和忽略任何负值来解决这个问题,因为我可以想象这会使事情变得更加复杂。
答案 0 :(得分:2)
如何使用Set::IntSpan?
use Set::IntSpan;
my @starts = (100,100,200,300,400,500,525);
my @ends = (150,125,250,350,450,550,550);
my @spec = map { "$starts[$_]-$ends[$_]" } 0..$#starts;
my $p = Set::IntSpan->new(@spec);
print "$p\n";
答案 1 :(得分:1)
使用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;
}
}
P.S。:如果有人认为perl是简洁的语言,那么在erlang中比较相同的算法spans
函数。我甚至不知道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_([]) -> [].
答案 2 :(得分:0)
使用一些列表转换:
my @starts = (100,100,200,300,400,500,525);
my @ends = (150,125,250,350,450,550,550);
my (%starts_seen, %ends_seen);
my @ar = sort { $a->[0] <=> $b->[0] } # result in ascending sort order of @starts
grep ! $starts_seen{$_->[0]}++,
sort { $b->[0] <=> $a->[0] } # descending sort b -> a
grep ! $ends_seen{$_->[1]}++,
sort { $b->[1] <=> $b->[1] } # descending sort b -> a
map [ $starts[$_],$ends[$_] ],
0 .. $#starts;
print "($_->[0],$_->[1]) " for @ar;
这导致:
(100,150) (200,250) (300,350) (400,450) (500,550)
此致
RBO
编辑:修改代码以反映排序的排序顺序