如何使用另一个文件中的值优化一个文件中的搜索?

时间:2015-03-27 20:46:00

标签: perl search hash

我有两种文件,比如文件A和文件B. 文件A有这样的行

scaffold10920   13740   14020   chr19.3.4051.27470346.27470626  280     100.00

文件B有这样的行

283     2       0       0       0       0       0       0       +       chr16.1.1.10933.11218   285     0       285     scaffold476     838469  193881  194166  1       285,    0,   193881,

前面的示例是每个文件中的一行。两个文件中的所有字段都是以制表符分隔的。

我想通过仅保留与文件A中的第一个和第四个字段具有相同值的行来过滤文件B(例如scaffold10920chr19.3.4051.27470346.27470626)。为此,我为此文件A制作了一个哈希表

{chr19.3.4051.27470346.27470626} -->  scaffold10920

我正在文件B中搜索。

这是我的剧本:

#!/app/languages/perl/5.14.2/bin/perl
use strict;
use warnings;

use Data::Dumper;

my $chromosome = $ARGV[0];
my @mykeys     = `cat rightChromosome/$chromosome.scaffolds.txt| sort -u`;

my %hces_hash;
foreach my $key_line (@mykeys) {

    #$key_line = $_;
    chomp($key_line);
    my @token = split('\t', $key_line);
    my $hce   = $token[3];
    my $scaff = $token[0];
    $hces_hash{$hce} = $scaff;
}

#print Dumper(\%hces_hash);

foreach my $key (keys %hces_hash) {

    chomp($key);

    my $scaffold = $hces_hash{$key};

    my $command  = "cat psl_best/$chromosome.best.psl|grep -w $key";
    my @belongs  = `$command`;
    chomp(@belongs);

    my $count = scalar(@belongs);

    foreach my $element (@belongs) {

        my @element_token = split('\t', $element);
        my $scaff_psl     = $element_token[13];
        my $hce_name      = $element_token[9];

        if ($scaffold eq $scaff_psl) {

            #print "$element\n";
            open FILE, ">>psl_raw/$chromosome.best.raw.psl" or die $!;
            print FILE "$element\n";
        }
    }

我的脚本正在运行,但速度非常慢。有没有办法优化它?

1 个答案:

答案 0 :(得分:2)

这将更快地工作,因为它只读取每个文件一次。我没有能够测试它,因为我没有数据,但我检查它编译。您可能想要更改某些变量的名称,但我已经做出了最好的猜测。

它的工作原理是使用 文件的字段4和支架文件的字段4构建哈希值,并在它们之间添加一个标签。哈希值无关紧要 - 只是一个正数。然后它读取最佳文件并从字段14和10构建相同的密钥,并在将记录打印到输出文件之前检查是否出现在哈希中。

你不应该在Perl之外做一些简单的事情,比如阅读文件。只有当你需要做一些超出Perl功能的事情时才有必要。我在sort调用中根本没有看到任何一点,因为它只是花时间来订购一旦存储在哈希值中将再次无序的数据。

#!/app/languages/perl/5.14.2/bin/perl
use strict;
use warnings;
use 5.010;
use autodie;

our @ARGV = qw/ chr2 /;

chdir 'psl_files';

my $raw_dir = 'psl_raw';

if ( -e $raw_dir ) {
  die qq{Can't make "$raw_dir"\n} unless -d $raw_dir;
  # ' fix highlighting
}
else {
  mkdir $raw_dir;
}

my ($chromosome) = @ARGV or die "Usage: $0 <chromosome>\n";

my $scaff_file = "rightChromosome/$chromosome.scaffolds.txt";
my $best_file  = "psl_best/$chromosome.best.psl";
my $raw_file   = "psl_raw/$chromosome.best.raw.psl";

# For provided data
$scaff_file = "chr2.scaffolds.txt";
$best_file  = "chr2.best_noHeaded.psl";

open my $scaff_fh, '<', $scaff_file;
my %hces_hash;
while ( <$scaff_fh> ) {
  chomp;
  my @fields = split /\t/;
  my $key = join "\t", @fields[0,3];
  ++$hces_hash{$key};
}
close $scaff_fh;

open my $best_fh, '<', $best_file;
open my $raw_fh,  '>', $raw_file;
while ( <$best_fh> ) {
  chomp;
  my @fields = split /\t/;
  my $key = join "\t", @fields[13,9];
  print $raw_fh "$_\n" if $hces_hash{$key};
}
close $raw_fh;
close $best_fh;