根据列 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;
}
我有一个制表符分隔的文件,第一列中有重复的值。第一列中的单个但重复的值对应于第二列中的多个值。它看起来像这样:
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;
}