【问题标题】:Parsing file based on column ID: perl基于列ID解析文件:perl
【发布时间】:2016-12-19 19:06:41
【问题描述】:

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

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

【问题讨论】:

  • 您可能还想从循环中删除文件写入,或者您将用每一行数据写入它。

标签: perl parsing hash multiple-columns subroutine


【解决方案1】:

我仍然会推荐一个哈希。但是,您将与同一 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 的所需文件,每个文件都有相应的三行。例如,如果应该拆分由| 分隔的项目,您可以在写出时执行此操作。

评论

  • 在我们 push 时创建密钥 $seqs{$id} 的匿名数组,如果还没有的话

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

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


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

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

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

【讨论】:

  • 感谢您的帮助和富有洞察力的 cmets。我注意到在您的回复中,“关闭 $fh_in;”应该是真正的“关闭 $in_fh;”。另外,关于我问题的后半部分,您有什么技巧可以在每个文件的名称后面加上该特定文件中包含的序列数吗?再次感谢您的大力帮助!!!
  • @Rob 感谢这些 cmets!我喜欢将文件句柄标记为$specs_fh——会更正。而且,我忘记了您将计数添加到名称的要求,现在将添加。感谢您的署名。
  • @Rob 我将计数添加到文件名中。 scalar返回一个列表的长度(元素个数),数组引用可以通过解引用作为列表使用,@{ array_ref },所以真的很简单。我将文件名中的计数用_ 分隔,如果您真的希望. 请将'_' 更改为'.'
  • 完成这段代码非常令人兴奋!不仅完成了,而且做得很好而且很快。非常感谢@zdim。
  • @Rob 哦,谢谢,很高兴听到这个消息。我很高兴它对你有用 :) 如果有任何其他澄清或 cmets 等有用的话,请告诉我。
猜你喜欢
  • 2016-01-22
  • 2012-06-08
  • 2018-08-28
  • 2019-05-19
  • 1970-01-01
  • 2012-10-09
  • 1970-01-01
  • 2019-10-10
  • 2016-07-31
相关资源
最近更新 更多