在文件/数组中,搜索哈希键,并将其替换为哈希值,对所有哈希键/值执行此操作



我在网站上搜索过,令人惊讶的是,我似乎找不到能解决我特定问题的东西。所以我想我应该把它发布出来,看看你们中一些更有经验的程序员如何解决这个问题。

我有一个类似电子表格的文本文件(许多行带有制表符分隔的列),我想在其中搜索某些标签(例如scaffold1253.1_size81005.632799_7496),并用更简化的标签(例如scaffold1253.1)替换它们。这些标签只在文本文件的第一列中。我已经编写了这个脚本,这样我就有了一个散列,其中旧标签是键,新标签是它们各自的值。这个散列大约有26000行。因此,从本质上讲,我想将散列键1乘1,在文本文件中搜索它们,并用它们各自的散列值替换它们。

我有一个很好的服务器,所以如果它太复杂了,无法使第一列特定于加快进程,那也没关系

这就是我目前所拥有的:

 use warnings;  

$gtf = './Hc_genome/Hc_rztk_1+2+8+9.augustus.gtf'; 
    open(FASTAFILE2, $gtf);
    @gtfarray = <FASTAFILE2>;
    #print @gtfarray;

my %hash;
while (<>)
{
   chomp;
   my ($key, $val) = split /t/;
   $hash{$key} .= exists $hash{$key} ? ",$val" : $val;
}
#print %hash;
while (my ($find, $replace) = each %hash) {
    foreach (@gtfarray){
        $_ =~ s/$find/$replace/g;
        push @newgtf, $_;   
    }
}
print @newgtf;

这段代码似乎不起作用,因为它并不完整。我确信这是foreach循环结构的问题。对不起,我不知道还有什么别的办法。有人有更好的方法来浏览这个文件并进行替换吗?

如有任何意见,我们将不胜感激!谢谢,

Andrew

@DVK-

这是你的mods的完整脚本,它在while循环中遇到语法错误,你知道它为什么不接受它吗?再次感谢!

use warnings;  
$gtf = './Hc_genome/Hc_rztk_1+2+8+9.augustus.gtf'; 
    open(FASTAFILE2, $gtf);
my %hash;
while (<>){
    chomp;
    my ($key, $val) = split /t/;
    $hash{$key} .= exists $hash{$key} ? ",$val" : $val;
}

while $line (<FASTAFILE2>){
    my @fields = split(/t/, $line);
    # If you only care about first column, don't need the foreach loop below;
    #    just do the loop insides on $fields[0]
    foreach my $field (@fields) {
        $field = $hash{$field} if exists $hash{$field};
        print $outfile "$fieldt"; # Small bug - will print training t
    }
    print $outfile "n"
}
__END__

以下是语法错误:perl gtf_mod2.pl<Hc_genome/header_file.txtgtf_mod2.pl第14行"while$line"附近出现语法错误gtf_mod2.pl第23行"}"附近出现语法错误由于编译错误,gtf_mod2.pl的执行中止。

第一次使用初始$find$replace键/值对通过循环耗尽文件。

有两种潜在的解决方案:

  1. 在while循环的每次迭代期间打开文件以进行读取(昂贵)
  2. 将foreach循环移到while的外部,每次迭代哈希(成本较低)

示例:

REPLACE:
for my $line (@gtfarray) {
   while(my ($find, $replace) = each %hash) {
      if($line =~ s/$find/$replace/g) {
         push @newgtf, $line;
         next REPLACE; # skip to next iteration
      }
   }
   # if there was no replacement, push the old line
   push @newgtf, $line
}  

替换第一列的文件有多大?

如果它>50000行,您最好执行反向

  • 遍历一次散列文件,并将该散列存储在内存中

  • 遍历主文件一次,对于每一行、每一列,在存储的哈希中找到该值,如果找到,则替换为哈希值,然后写入。

换句话说,删除第一个@gtfarray = <FASTAFILE2>;,并将最后一个while循环替换为:

while my $line (<FASTAFILE2>) {
    my @fields = split(/t/, $line);
    # If you only care about first column, don't need the foreach loop below;
    #    just do the loop insides on $fields[0]
    foreach my $field (@fields) {
        $field = $hash{$field} if exists $hash{$field};
        print $outfile "$fieldt"; # Small bug - will print training t
    }
    print $outfile "n";
}

注意:我假设这些字段包含哈希键的完整内容(例如,您的数据文件将包含一个带有"scaffold1253.1_size81005.632799_7496"的字段,而不是一个带有"XYZscaffold1250.1_size81007.632799,7496___IOU"的字段)。

如果这种假设是错误的,并且您确实需要运行正则表达式,因为您的脚手架字符串可能包含在较长的字符串中,那么除了运行O(N*M)正则表达式之外,可能还有更好的解决方案:如果您的脚手架串都是某个定义良好的格式(例如"scaffoldNNNNN.NNN_sizeNNN.NNN.NNN.NNN.NNNN_NNNN"),那么您需要做的是:

  • 对于数据文件的每一行,运行一个正则表达式来查找该模式,整个模式位于捕获组括号内:

    @matches = ($line =~ m/(scaffoldd+.d+_sized+.d+.d+_d+/g );
    
  • 然后,在散列中查找@matchs数组的每个值。如果找到,则仅将匹配项作为s////正则表达式运行。

看看你之前的文章,在读取文件时创建缩短的"id"不是更简单吗。那么你就不需要另一个文件了?

下面是(未经测试的)代码。(需要将print语句定向到命令行上的输出文件,或者打开一个文件在脚本中写入)。

#!/usr/bin/perl
use strict;
use warnings;
my $gtf = './Hc_genome/Hc_rztk_1+2+8+9.augustus.gtf';
open my $FASTAFILE2, "<", $gtf or die "Unable to open '$gtf' for reading. $!";
my %seen;
while (<$FASTAFILE2>) {
    chomp;
    my ($id, $val) = split /t/, $_, 2;
    # copy $id to $prefix and
    # remove everything after '.1' in $prefix
    (my $prefix = $id) =~ s/.1K.*//; 
    if ($seen{$id}) {
        ++$seen{$id};
    }
    else {
        $seen{$id} = 'a';   
    }
    print "$prefix$seen{$id}t$valn";
}
close $FASTAFILE2 or die "Unable to close '$gtf' from reading. $!";

这会是Tie::File的作业吗?假设,也就是说,数据文件可以作为一个数组进行操作。

use Tie::File; 
my $file = "./Hc_genome/Hc_rztk_1+2+8+9.augustus.gtf"; 
tie @lines, 'Tie::File', $file or die ;
for (@lines) {
 s/Oldlabel/NewLable/g;   # Change this to fit
}
untie @lines ;

Tie::File做了一系列技巧来保持对文件内存的"原位"更改的有效性。

相关内容

  • 没有找到相关文章