根据列 ID 解析文件:perl

Parsing file based on column ID: perl

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

    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;
            }
     }

我仍然会推荐散列。但是,您将与同一 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 之后创建的,如果还没有的话

  • 如果制表符有问题(转换为 spaces?),请使用 ' '。见评论

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


split 的默认模式是 ' ',也会触发特定行为——它匹配“任何连续的白色space”,并且还省略了前导白色space。 (模式 / / 匹配单个 space,关闭 ' ' 的这种特殊行为。)请参阅 split page. Thus it is advisable to use ' ' when splitting on unspecified number of spaces, since in the case of split this is a bit idiomatic, is perhaps the most common use, and is its default. Thanks to Borodin 上更精确的描述以提示此评论和更新(原始 post 具有等效的 /\s+/)。

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

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