Perl脚本比grep -f更快

时间:2015-11-26 01:43:24

标签: perl grep

我正在调整此处提出的现有perl脚本: Fast alternative to grep -f

我需要过滤许多非常大的文件(地图文件),每个文件大约1000万行x5个字段宽,使用一个长列表(过滤文件)和匹配的地图文件中的打印行。我尝试使用grep -f,但它只是花了太长时间。我读到这种方法会更快。

这就是我的文件:

过滤文件:

DB775P1:276:C2R0WACXX:2:1101:10000:77052
DB775P1:276:C2R0WACXX:2:1101:10003:51920
DB775P1:276:C2R0WACXX:2:1101:10004:36433
DB775P1:276:C2R0WACXX:2:1101:10004:57256

地图文件:

DB775P1:276:C2R0WACXX:2:1101:10000:70401     chr5    21985760    21985780    - 
DB775P1:276:C2R0WACXX:2:1101:10000:77052     chr18   14723904    14723924    - 
DB775P1:276:C2R0WACXX:2:1101:10000:77052     chr18   14745586    14745606    - 
DB775P1:276:C2R0WACXX:2:1101:10000:77052     chr4    7944241     7944261     - 
DB775P1:276:C2R0WACXX:2:1101:10000:77052     chr4    8402856     8402876     + 
DB775P1:276:C2R0WACXX:2:1101:10000:77052     chr8    10864708    10864728    + 
DB775P1:276:C2R0WACXX:2:1101:10002:88487     chr17   5681227     5681249     - 
DB775P1:276:C2R0WACXX:2:1101:10004:74842     chr13   2569168     2569185     + 
DB775P1:276:C2R0WACXX:2:1101:10004:74842     chr14   13253418    13253435    - 
DB775P1:276:C2R0WACXX:2:1101:10004:74842     chr14   13266344    13266361    -

我希望输出行看起来像这样,因为它们包含map和filter文件中的字符串。

DB775P1:276:C2R0WACXX:2:1101:10000:77052     chr18   14723904    14723924    - 
DB775P1:276:C2R0WACXX:2:1101:10000:77052     chr18   14745586    14745606    - 
DB775P1:276:C2R0WACXX:2:1101:10000:77052     chr4    7944241     7944261     - 
DB775P1:276:C2R0WACXX:2:1101:10000:77052     chr4    8402856     8402876     + 
DB775P1:276:C2R0WACXX:2:1101:10000:77052     chr8    10864708    10864728    + 

这是我到目前为止编辑的脚本,但没有运气:

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

# Load the files
my $filter = $ARGV[0];
my $sam = $ARGV[1];
open FILE1, $filter;
   if (! open FILE1, $filter) {die "Can't open filterfile: $!";}
open FILE2, $sam;
   if (! open FILE2, $sam) {die "Can't open samfile: $!";}

# build hash of keys using lines from the filter file
my $lines;
my %keys
while (<FILE1>) {
   chomp $lines;
   %keys = $lines;
}
close FILE1;

# look up keys in the map file, if match, print line in the map file.
my $samlines;
while (<FILE2>) {
   chomp $samlines;
   my ($id, $chr, $start, $stop, $strand)  = split /\t/, $samline;
   if (defined $lines->{$id}) { print "$samline \n"; }
}

2 个答案:

答案 0 :(得分:5)

你似乎没有真正尝试过自己解决这个问题。您展示的代码甚至无法编译

有几个原因导致它无效

  • 您正在使用带有隐式控制变量的文件读取循环,这些控制变量将每行读入$_,但您希望数据能够显示在$lines$samlines中。您还使用了$samline,但您甚至没有声明

  • 该行

    my %keys
    

    最后需要一个分号

  • 我不知道您对$lines的期望,但是为这样的哈希分配标量值

    %keys = $lines;
    

    将在哈希分配中生成警告奇数个元素,并为您留下仅包含单个元素的哈希

这是一个Perl程序,可以执行我认为您的意图,但我不能说它是否会比command_line grep快得多。请注意,我使用了autodie pragma而不是显式测试每个文件IO操作的状态

#!/usr/bin/env perl

use strict;
use warnings;
use v5.10.1;
use autodie;

my ($filter_f, $sam_f) = @ARGV;

my %filter;

{
    open my $fh, '<', $filter_f;

    while ( <$fh> ) {
        $filter{$1} = 1 if /(\S+)/;
    }
}

open my $fh, '<', $sam_f;

while ( <$fh> ) {
    print if /(\S+)/ and $filter{$1};
}

输出

DB775P1:276:C2R0WACXX:2:1101:10000:77052     chr18   14723904    14723924    -
DB775P1:276:C2R0WACXX:2:1101:10000:77052     chr18   14745586    14745606    -
DB775P1:276:C2R0WACXX:2:1101:10000:77052     chr4    7944241     7944261     -
DB775P1:276:C2R0WACXX:2:1101:10000:77052     chr4    8402856     8402876     +
DB775P1:276:C2R0WACXX:2:1101:10000:77052     chr8    10864708    10864728    +

答案 1 :(得分:0)

因此,鲍罗丁提出的脚本确实有效。但是,我发现我的文件太大而无法完成。相反,我使用&#39; sort&#39;对两个文件进行了排序。然后跟着加入。

join -1 1 -2 1 filter.file map.file > filtered.map

对于48个作业中的每一个,我保留了16G的RAM和8个处理器。

谢谢大家的帮助!