嵌套循环运行得非常慢

时间:2014-10-31 09:51:29

标签: perl loops nested

我正在尝试运行一个程序来检查一个文件的每一行与第二个文件的每一行,以查看是否有一些元素匹配。每个文件大约200k行。

到目前为止我看到的是这样的;

#!/usr/bin/perl
#gffgenefind.pl
use strict;
use warnings;

die "SNP gff\n" unless @ARGV == 4;
open( my $snp, "<", $ARGV[0] ) or die "Can't open $:";
open( my $gff, "<", $ARGV[1] ) or die "can't open $:";
open( my $outg, ">", $ARGV[2] );
open( my $outs, ">", $ARGV[3] );
my $scaffold;
my $site;
my @snplines = <$snp>;
my @gfflines = <$gff>;
foreach my $snpline (@snplines) {
    my @arr = split( /\t/, $snpline );
    $scaffold = $arr[0];
    $site     = $arr[1];

    foreach my $line (@gfflines) {
        my @arr1 = split( /\t/, $line );
        if ( $arr1[3] <= $site and $site <= $arr1[4] and $arr1[0] eq $scaffold ) {
            print $outg "$line";
            print $outs "$snpline";
        }
    }
}

文件1(snp)看起来像scaffold_100 10689 A C A 0 0 0 0 0 0 文件2(gff)看起来像scaffold_1 phytozomev10 gene 750912 765975 . - . ID=Carubv10008059m.g.v1.0;Name=Carubv10008059m.g

基本上,我想查看第一个值是否匹配,以及来自snp的第二个值是否在第二个文件(在这种情况下为750912765975)中定义的范围内

我已经看到要避免使用嵌套循环,并且想知道是否有另一种方法让我查看这些数据。

谢谢!

2 个答案:

答案 0 :(得分:1)

首先 - 丢失foreach循环。当你可能不需要时,它会将你的整个文件读入内存。

尝试改为:

while ( my $snpline = <$snp> ) {

因为它逐行读取。

通常 - 混合数组指标和命名变量也是不好的风格。

核心问题很可能是因为你的第一个文件的每一行都在循环所有第二个文件。

编辑:注意 - 因为&#39;脚手架&#39;并不是唯一的,相应的修改

这似乎是使用哈希的好地方。例如。

my %sites; 

while ( <$snp> ) {
    my ( $scaffold, $site ) = split ( /\t/ );
    $sites{$site}{$scaffold}++ 
}

while ( <$gff> ) {
     my ( $name, $tmp1, $tmp2, $range_start, $range_end ) = split ( /\t/ );
     if ( $sites{$name} ) {
          foreach my $scaffold ( keys %{ $sites{$name} ) {
             if ( $scaffold > $range_start
              and $scaffold < $range_end ) { 
                  #do stuff with it;
                  print;
             }
          }
     }         
}

希望你能得到主旨,即使它不具备你所追求的目标吗?

答案 1 :(得分:-1)

试试这个Python摘要:

#!/usr/bin/env python
import sys
import contextlib
if len(sys.argv) !=5:
   raise Exception('SNP gff')
snp, gff, outg, outs = sys.argv[1:]

gff_dict = {}
with open(gff) as gff_handler:
    for line in gff_handler:
        fields=line.split()
        try:
            gff_dict[fields[0]].append(fields[1:])
        except KeyError:
            gff_dict[fields[0]] = [fields[1:]]

with contextlib.nested(open(snp),
                       open(outs, 'w'),
                       open(outg, 'w')) as (snp_handler,
                                            outs_handler,
                                            outg_handler):
    for line_snp in snp_handler:
        fields=line_snp.split()
        key = fields[0]
        if key in gff_dict:
            for ele in gff_dict[key]:
                if ele[2] <= fields[1] <= ele[3]:
                    outs_handler.write(line_snp)
                    outg_handler.write("{0}\t{1}\n".format(key,"\t".join(ele)))