根据列ID解析文件:perl

时间:2016-08-12 17:30:04

标签: perl parsing hash multiple-columns subroutine

我在第一列中有一个带有重复值的制表符描述文件。第一列中的单个但重复的值对应于第二列中的多个值。它看起来像这样:

    AAAAAAAAAA1     m081216|101|123
    AAAAAAAAAA1     m081216|100|1987
    AAAAAAAAAA1     m081216|927|463729
    BBBBBBBBBB2     m081216|254|260489
    BBBBBBBBBB2     m081216|475|1234
    BBBBBBBBBB2     m081216|987|240
    CCCCCCCCCC3     m081216|433|1000
    CCCCCCCCCC3     m081216|902|366 
    CCCCCCCCCC3     m081216|724|193 

对于第一列中的每种类型的序列,我试图打印到只包含与其对应的序列的文件。文件名应包括第一列中的重复序列以及第二列中与其对应的序列数。在上面的例子中,因此我将有3个文件,每个文件有3个序列。第一个文件的名称类似于“AAAAAAAAAA1.3.txt”,打开后如下所示:

    m081216|101|123
    m081216|100|1987
    m081216|927|463729

我已经看过其他类似的问题,但是他们已经使用哈希回答了问题。我不认为我不能使用哈希,因为我需要保持列之间的关系数量。也许有办法使用散列哈希?我不确定。 到目前为止,这是我的代码。

    use warnings;
    use strict;
    use List::MoreUtils 'true';

    open(IN, "<", "/path/to/in_file") or die $!;

    my @array;
    my $queryID;

    while(<IN>){
            chomp;
            my $OutputLine = $_;
            processOutputLine($OutputLine);
    }


    sub processOutputLine {
            my ($OutputLine) = @_;
            my @Columns = split("\t", $OutputLine);
            my ($queryID, $target) = @Columns;
            push(@array, $target, "\n") unless grep{$queryID eq $_} @array;
            my $delineator = "\n";
            my $count = true { /$delineator/g } @array;
            open(OUT, ">", "/path/to/out_$..$queryID.$count.txt") or die $!;
            foreach(@array){
                    print OUT @array;
            }
     }

1 个答案:

答案 0 :(得分:3)

我仍然会推荐哈希。但是,您将与相同ID相关的所有序列存储在匿名数组中,该数组是该ID键的值。这真的是两行代码。

use warnings;
use strict;
use feature qw(say);

my $filename = 'rep_seqs.txt';   # input file name
open my $in_fh, '<', $filename or die "Can't open $filename: $!";

my %seqs;
foreach my $line (<$in_fh>) {
    chomp $line;
    my ($id, $seq) = split /\t/, $line;
    push @{$seqs{$id}}, $seq;
}
close $in_fh;

my $out_fh;
for (sort keys %seqs) {
    my $outfile = $_ . '_' . scalar @{$seqs{$_}} . '.txt';
    open $out_fh, '>', $outfile  or do {
        warn "Can't open $outfile: $!";
        next;
    };
    say $out_fh $_ for @{$seqs{$_}};
}
close $out_fh;

通过输入,我得到了所需的文件,名为AA..._count.txt,每个文件对应三行。如果分隔|的项目应该被拆分,那么你可以在写出来时这样做,例如。

评论

  • 我们$seqs{$id}创建了密钥push的匿名数组,如果没有,则

  • 如果标签出现问题(转换为空格?),请使用' '。见评论。

  • 每个open关闭并重新打开文件句柄,因此无需每次都关闭

split的默认模式是' ',也触发特定行为 - 它匹配“任何连续的空格”,并且还省略了前导空格。 (模式/ /匹配单个空格,关闭' '的这种特殊行为。)在split页面上查看更精确的说明。因此,建议在拆分未指定数量的空格时使用' ',因为在split的情况下这有点惯用,可能是最常用的,并且是它的默认值。感谢Borodin提示此评论和更新(原始帖子具有等效的/\s+/)。

请注意,在这种情况下,由于' '$_的默认值,我们可以将其缩短一点

for (<$in_fh>) {
    chomp;
    my ($id, $seq) = split;
    push @{$seqs{$id}}, $seq;
}