查找与多个范围perl重叠的所有值的总和

时间:2018-12-17 22:51:21

标签: perl

我有两个文件结构,如下所示:

间隔:

chr1    121087394   121087399
chr1    121087820   121087822
chr20   1934714     1934716
chr3    108047283   108047285

深度:

chr1 121087395 A 3799
chr1 121087396 T 3818
chr1 121087397 G 3824
chr1 121087398 T 3827
chr1 121087399 G 3831
chr1 121087821 T 2499
chr1 121087822 T 2506
chr20 1934715  G 2650
chr20 1934716  T 2661
chr3 108047284 T 1755
chr3 108047285 C 1750

我想要输出,其中第4列是深度文件第4列中所有值的特定范围内的所有值的总和。 输出:

    chr1 121087395 121087399 19099
    chr1 121087821 121087822 5005
    chr20 1934715  1934716   5331
    chr3  108047284 108047285 3505

我的代码如下:

#!/usr/bin/perl
use strict;
use warnings;

my $intervals = $ARGV[0];
my $depth = $ARGV[1];

my $args = $#ARGV+1;


my ($FI, $FD, @F, $i_chr, $i_start, $i_end, @diff, $i, $j);
my $z; 
my $nr=0;
my $sum=0;
open($FI, '<', $intervals) or die "Could not open file: $intervals\n";

while(<$FI>){
    chomp $_;
    ($i_chr, $i_start, $i_end) = split("\t", $_);
    open($FD, '<', $depth) or die "Could not open file: $depth\n";
    while(<$FD>){
    chomp $_;
    @F = split("\t", $_);
    if($F[0] eq $i_chr && $F[1] > $i_start && $F[1] <= $i_end){
        $nr++;
        $sum += $F[3];
    }
    }print "$sum\n";
}

if循环不起作用。它正在打印深度文件第4列的所有值的总和。

如何修改此循环?

2 个答案:

答案 0 :(得分:2)

示例输出中的许多数字与您对所做操作的描述以及示例输入中的数字不匹配-事情加起来不对劲,数字超出范围,等等。您的示例输入,输出或描述是错误的,我不确定是哪个。另外,您的示例代码不会产生任何与预期输出格式相近的东西(对于每个间隔范围,该名称似乎是该名称,该范围内的最小和最大深度以及最后一列的总和)。 ..

仍然如此,这就是我认为的尝试:

#!/usr/bin/perl
use warnings;
use strict;
use feature qw/say/;
use autodie;

# Read the depths file into a hash table to avoid re-reading it for
# every line of the intervals file.
my %depths;
open my $depth, "<", $ARGV[1];
while (<$depth>) {
  chomp;
  my @F = split /\t/;
  push @{$depths{$F[0]}}, [ $F[1], $F[3] ];
}

open my $intervals, "<", $ARGV[0];
$, = "\t";
while (<$intervals>) {
  chomp;
  my @F = split /\t/;
  my $sum = 0;
  my ($min, $max);
  for my $d (@{$depths{$F[0]}}) {
    if ($d->[0] >= $F[1] && $d->[0] <= $F[2]) {
      $sum += $d->[1];
      $min = $d->[0] if !defined $min || $d->[0] < $min;
      $max = $d->[0] if !defined $max || $d->[0] > $max;
    }
  }
  say $F[0], $min, $max, $sum;
}

请注意zdim注释中提到的所有内容:范围更严格的变量(导致不在新间隔之间保留先前的值),并且仅读取深度文件一次,而不是间隔文件的每一行一次,从而使其更有效率。

答案 1 :(得分:1)

有点类似于Shawn的解决方案,但我使用的是哈希哈希,而不是数组的哈希。另外,我没有像Shawn对minmax那样调整边界。

#!/usr/bin/perl
use strict;
use warnings;

my %int;
open my $fh, '<', 'f2.txt' or die $!;
# depth file
while (<$fh>) {
    my ($chr, $num, $amt) = (split)[0,1,3];
    $int{$chr}{$num} = $amt;
}
close $fh or die $!;

open $fh, '<', 'f1.txt' or die $!;

# intervals file
while (<$fh>) {
    chomp;
    my ($chr, $start, $stop) = split;

    my $href = $int{$chr}; # hash reference
    my $sum = 0;
    for my $num (keys %$href) {
        if ($start <= $num && $num <= $stop) {
            $sum += $href->{$num};
        }   
    }
    print "$_\t$sum\n";

}
close $fh or die $!;

结果是:

chr1    121087394   121087399   19099
chr1    121087820   121087822   5005
chr20   1934714     1934716     5311
chr3    108047283   108047284   3505

编辑:OP更改了她的输入。我在最后一行输出中进行了更改以反映这一点。她在比赛第三行报告了“ 5331”,但正确的数字是“ 5311”