我有3列一个长长的清单的文本文件。
输入文件:
XIGO XIGO_24480 Xigou
XIGO XIGO_24481 Xigou
XOLO XOLO_Z1E01 Xoloitzcuintle
XOLO XOLO_Z1G01 Xoloitzcuintle
YORK TYo_0GT393 Yorkshire Terrier
YORK TYo_0GT394 Yorkshire Terrier
我想用数字标签输出的文本文件。由第三列拆分列表。
File_1.txt
XIGO XIGO_24480
XIGO XIGO_24481
File_2.txt
XOLO XOLO_Z1E01
XOLO XOLO_Z1G01
File_3.txt
YORK TYo_0GT393
YORK TYo_0GT394
我尝试将文件与哈希函数分裂在Perl。不过,我仍然不能得到正确的文件。
#!/usr/bin/perl -w
use strict;
use warnings;
my $input = 'File_List_1.txt';
my %results;
my $out;
my $FID;
my $IID;
my $Breed;
my $results;
my @array;
my $index=0;
open(my $fh, '<', $input) or die "cannot open input file: $!";
while (<$fh>) {
chomp;
my ($FID, $IID, $Breed) = split '\t', $_;
$results{$Breed}{$IID} = $FID;
}
for my $values (keys %results) {
open (my $out, '>', 'File_',"$index.txt") or die "cannot open input file: $!";
for my $values_1 (keys %{$results{$values}}){
print $out, join ("\t" , map {$results{$values}->{$values_1},$values_1} keys%results);
}
close $out;
有给我什么建议吗?谢谢
我认为这是你在找什么:
#!/usr/bin/perl
use strict;
use warnings;
my $index = 1;
my %seen;
while (<STDIN>) {
chomp;
my($start, $key) = /^(\S+\s+\S+)\s+(.+)\s*$/;
unless ($seen{$key}) {
# new key detected, we need to open new file
open(my $fh, '>', "File_${index}.txt")
or die "can't open new file: $!\n";
$seen{$key} = $fh;
$index++;
}
my $fh = $seen{$key};
print $fh "${start}\n";
}
# close files
close $_ foreach (values %seen);
exit 0;
测试运行:
$ perl dummy.pl <dummy.txt
$ cat File_1.txt
XIGO XIGO_24480
XIGO XIGO_24481
$ cat File_2.txt
XOLO XOLO_Z1E01
XOLO XOLO_Z1G01
$ cat File_3.txt
YORK TYo_0GT393
YORK TYo_0GT394
注:出于全面考虑:上述解决方案将一个标准的Linux机器上运行到too many open files
错误,如果你的投入已经超过1000〜键。你将不得不使用ulimit
增加限制,或预排序的数据,可以使用下面的优化版本。或将所有数据保存在内存和循环结束后,将文件写入。
编辑:如果您确信密钥不输入文件,例如重复此可以进行优化
my $fh;
while (<STDIN>) {
chomp;
my($start, $key) = /^(\S+\s+\S+)\s+(.+)\s*$/;
unless ($seen{$key}++) {
# new key detected, we need to open new file
if ($fh) {
close($fh) or die "close: $!\n";
}
open($fh, '>', "File_${index}.txt")
or die "can't open new file: $!\n";
$index++;
}
print $fh "${start}\n";
}
# make sure to close last open file
close($fh) or die "close: $!\n";
我不知道你的真实的输入数据是什么样子,但如果输出的顺序是不相关的,那么你可以在bash输入数据与此优化的版本预先排序:
$ sort -t $'\t' -k 3 dummy.txt | perl dummy.pl
EDIT2如果你想保持原来的split()
的方法:
# remove trailing whitespace
s/\s+$//;
my($FID, $IID, $key) = split('\t', $_);
...
print $fh "${FID}\t${IID}\n";
虽然AWK是不标记,它最适合在这种情况下。如果您想尝试,这里是你怎么做
$ cat victor.txt
XIGO XIGO_24480 Xigou
XIGO XIGO_24481 Xigou
XOLO XOLO_Z1E01 Xoloitzcuintle
XOLO XOLO_Z1G01 Xoloitzcuintle
YORK TYo_0GT393 Yorkshire Terrier
YORK TYo_0GT394 Yorkshire Terrier
$ awk ' { curr=$1; if(prev!=curr) { x++ } print $1, $2, "File_" x ".txt" ; prev=curr } ' victor.txt
XIGO XIGO_24480 File_1.txt
XIGO XIGO_24481 File_1.txt
XOLO XOLO_Z1E01 File_2.txt
XOLO XOLO_Z1G01 File_2.txt
YORK TYo_0GT393 File_3.txt
YORK TYo_0GT394 File_3.txt
$ ls File_1.txt File_2.txt File_3.txt
/bin/ls: cannot access File_1.txt: No such file or directory
/bin/ls: cannot access File_2.txt: No such file or directory
/bin/ls: cannot access File_3.txt: No such file or directory
上述AWK打印我们需要的结果。 AWK可以将输出重定向到文件
$ awk ' { curr=$1; if(prev!=curr) { x++ } print $1, $2 > "File_" x ".txt" ; prev=curr } ' victor.txt
$ ls File_1.txt File_2.txt File_3.txt
File_1.txt File_2.txt File_3.txt
$ cat File_1.txt
XIGO XIGO_24480
XIGO XIGO_24481
$ cat File_2.txt
XOLO XOLO_Z1E01
XOLO XOLO_Z1G01
$ cat File_3.txt
YORK TYo_0GT393
YORK TYo_0GT394
$