从重叠范围中获取最大范围

时间:2018-07-30 16:24:10

标签: perl unix

我有一个带范围的文件。我想要列表中的最高范围,并删除其他小的重叠范围:

chr1A   77568   86766
chr1A   203138  204427
chr1A   204428  222994
chr1A   204428  206534
chr1A   206538  207965
chr1A   207967  213097
chr1A   213098  221111
chr1A   213098  213863
chr1A   213864  214195
chr1A   214196  221111
chr1A   221112  222994
chr1A   222995  223876
chr1A   223882  227109
chr1A   305432  314629
chr1A   323643  325976
chr1A   431741  451601
chr1A   431741  435137
chr1A   435141  436568
chr1A   436570  441700
chr1A   441701  449710
chr1A   441701  442466
chr1A   442467  442798
chr1A   442799  449710
chr1A   449711  451601

例如:

第一个和第二个范围是唯一的,因此保留它们。

第3至第11个范围重叠,仅保留最高的chr1A 204428 222994,依此类推。

我想要这样的输出:

chr1A   77568   86766
chr1A   203138  204427
chr1A   204428  222994
chr1A   222995  223876
chr1A   223882  227109
chr1A   305432  314629
chr1A   323643  325976
chr1A   431741  451601

我希望在perl,bash或任何其他unix工具中获得解决方案。谢谢

1 个答案:

答案 0 :(得分:0)

这是蛮力方法的一个例子。对于每个间隔,我们检查它是否包含在其他任何间隔中。不用说,根据数据量(输入文件中的行数),这可能会变得很慢:

use feature qw(say);
use strict;
use warnings;

my $fn = 'input.txt';
open ( my $fh, '<', $fn ) or die "Could not open file '$fn': $!";
my @ranges;
while (my $line = <$fh> ) {
    chomp $line;
    my ( $chr, $low, $high ) = split " ", $line;
    push @ranges, {chr => $chr, range => [$low, $high]};
}
close $fh;
my @result;
RANGE: for my $i (0..$#ranges) {
    my ( $low, $high ) = @{ $ranges[$i]->{range} };
    for my $j (0..$#ranges) {
        next if $i == $j;
        my ($low2, $high2) = @{ $ranges[$j]->{range} };
        next RANGE if $low>= $low2 && $high<= $high2;
    }
    push @result, $ranges[$i];
}

for my $range (@result) {
    say join "\t", $range->{chr}, @{ $range->{range} };
}

输出

chr1A   77568   86766
chr1A   203138  204427
chr1A   204428  222994
chr1A   222995  223876
chr1A   223882  227109
chr1A   305432  314629
chr1A   323643  325976
chr1A   431741  451601