首页 > 解决方案 > 查找与多个范围重叠的所有值的总和 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 列的所有值的总和。

我怎样才能修改这个循环?

标签: perl

解决方案


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

尽管如此,这还是我认为你正在尝试做的事情:

#!/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 在评论中提到的所有事情:变量的范围更窄(导致在新间隔之间不保留以前的值),并且只读取深度文件一次,而不是间隔文件的每行一次,使其更多高效的。


推荐阅读