-1

I have two sets of ranges. Each range is a pair of integers (start and end) representing some sub-range of a single larger range. I need to determine which ranges from set A overlap with which ranges from set B.

4

1 回答 1

3

我认为您的输入被截断了,因为我看不到任何方法可以获取您预期输出的最后一行。

但是,对于那里的部分,我认为您需要这样的脚本:

my %cover;

foreach my $line ( <STDIN> )
{
    chomp $line;
    my ( $tag, $lo, $hi ) = split /\s+/, $line;
    map { $cover{$_}++ } ($lo .. $hi);
}


my $beg = 0;
my $end = 0;
my $cnt = 0;

foreach my $val ( sort { $a <=> $b } keys %cover )
{
    if ($cover{$val} != $cnt || $val > $end + 1)
    {
        if ($cnt > 0)
        {
            print "chr1\t$beg\t$end\t$cnt\n";
        }

        $cnt = $cover{$val};
        $beg = $val;
        $end = $val;
    } else
    {
        $end = $val;
    }
}

if ($cnt > 0)
{
    print "chr1\t$beg\t$end\t$cnt\n";
}

但是,您没有告诉我们如何处理chr1或如何在输入和输出之间关联它(例如,那里可能出现其他值吗?)所以我只是在输出中硬编码了它。您必须适当地更改该部分。

此外,我的脚本输出的范围与您的“预期输出”略有不同,特别是在两个范围相邻的地方。例如,我的脚本输出

chr1    556     579     1
chr1    580     592     2

但是您的预期输出给出580而不是579第一行。我不确定您的预期输出是否正确。如果你真的想要 580 那里(这没有多大意义),那么你可以修改上面的脚本以输出$end+1when $val == $end+1。但这似乎很奇怪。

这是代码的修改版本,当范围邻接时会出现奇怪的行为:

my %cover;

foreach my $line ( <STDIN> )
{
    chomp $line;
    my ( $tag, $lo, $hi ) = split /\s+/, $line;
    map { $cover{$_}++ } ($lo .. $hi);
}


my $beg = 0;
my $end = 0;
my $cnt = 0;

foreach my $val ( sort { $a <=> $b } keys %cover )
{
    if ($cover{$val} != $cnt || $val > $end + 1)
    {
        ## unusual value for '$end' when ranges abut.
        $end = $val if ($val == $end + 1);

        if ($cnt > 0)
        {
            print "chr1\t$beg\t$end\t$cnt\n";
        }

        $cnt = $cover{$val};
        $beg = $val;
        $end = $val;
    } else
    {
        $end = $val;
    }
}

if ($cnt > 0)
{
    print "chr1\t$beg\t$end\t$cnt\n";
}
于 2013-11-03T18:52:08.390 回答