我有多个csv文件,我想合并所有这些文件..... 我正在下面展示我的一些示例csv文件......
M1DL1_Interpro_sum.csv
IPR017690,Outer membrane, omp85 target,821
IPR014729,Rossmann,327
IPR013785,Aldolase,304
IPR015421,Pyridoxal,224
IPR003594,ATPase,179
IPR000531,TonB receptor,150
IPR018248,EF-hand,10
M1DL2_Interpro_sum.csv
IPR017690,Outer membrane, omp85 target,728
IPR013785,Aldolase,300
IPR014729,Rossmann,261
IPR015421,Pyridoxal,189
IPR011991,Winged,113
IPR000873,AMP-dependent synthetase/ligase,111
M1DL3_Interpro_sum.csv
IPR017690,Outer membrane,905
IPR013785,Aldolase,367
IPR014729,Rossmann,338
IPR015421,Pyridoxal,271
IPR003594,ATPase,158
IPR018248,EF-hand,3
现在合并这些文件我尝试了以下代码
@ARGV = <merge_csvfiles/*.csv>;
print @ARGV[0],"\n";
open(PAGE,">outfile.csv") || die"Can't open outfile.csv\n";
while($i<scalar(@ARGV))
{
open(FILE,@ARGV[$i]) || die"Can't open ...@ARGV[$i]...\n";
$data.=join("",<FILE>);
close FILE;
print"file completed...",$i+1,"\n";
$i++;
}
@data=split("\n",$data);
@data2=@data;
print scalar(@data);
for($i=0;$i<scalar(@data);$i++)
{
@id1=split(",",@data[$i]);
$id_1=@id1[0];
@data[$j]=~s/\n//;
if(@data[$i] ne "")
{
print PAGE "\n@data[$i],";
for($j=$i+1;$j<scalar(@data2);$j++)
{
@id2=split(",",@data2[$j]);
$id_2=@id2[0];
if($id_1 eq $id_2)
{
@data[$j]=~s/\n//;
print PAGE "@data2[$j],";
@data2[$j]="";
@data[$j]="";
print "match found at ",$i+1," and ",$j+1,"\n";
}
}
}
print $i+1,"\n";
}
merge_csvfiles是一个包含所有文件的文件夹
以上代码的输出是
IPR017690,Outer membrane,821,IPR017690,Outer membrane ,728,IPR017690,Outer membrane,905
IPR014729,Rossmann,327,IPR014729,Rossmann,261,IPR014729,Rossmann,338
IPR013785,Aldolase,304,IPR013785,Aldolase,300,IPR013785,Aldolase,367
IPR015421,Pyridoxal,224,IPR015421,Pyridoxal,189,IPR015421,Pyridoxal,271
IPR003594,ATPase,179,IPR003594,ATPase,158
IPR000531,TonB receptor,150
IPR018248,EF-hand,10,IPR018248,EF-hand,3
IPR011991,Winged,113
IPR000873,AMP-dependent synthetase/ligase
但我希望以下列格式输出....
IPR017690,Outer membrane,821,IPR017690,Outer membrane ,728,IPR017690,Outer membrane,905
IPR014729,Rossmann,327,IPR014729,Rossmann,261,IPR014729,Rossmann,338
IPR013785,Aldolase,304,IPR013785,Aldolase,300,IPR013785,Aldolase,367
IPR015421,Pyridoxal,224,IPR015421,Pyridoxal,189,IPR015421,Pyridoxal,271
IPR003594,ATPase,179,0,0,0,IPR003594,ATPase,158
IPR000531,TonB receptor,150,0,0,0,0,0,0
IPR018248,EF-hand,10,0,0,0,IPR018248,EF-hand,3
0,0,0,IPR011991,Winged,113,0,0,0
0,0,0,IPR000873,AMP-dependent synthetase/ligase,111,0,0,0
有谁知道我该怎么做? 谢谢你的帮助
答案 0 :(得分:1)
正如Miguel Prz的评论中所提到的,你没有解释你希望如何进行合并,但是,根据“所需的输出”样本判断,你想要的是连接所有匹配ID的行。三个输入文件放在输出文件的一行中,“0,0,0”代替给定文件中没有出现的任何行。
那么,那么:
#!/usr/bin/env perl
use strict;
use warnings;
my @input_files = glob 'merge_csvfiles/*.csv';
my %data;
for my $i (0 .. $#input_files) {
open my $infh, '<', $input_files[$i]
or die "Failed to open $input_files[$i]: $!";
while (<$infh>) {
chomp;
my $id = (split ',', $_, 2)[0];
$data{$id}[$i] = $_;
}
print "Input file read: $input_files[$i]\n";
}
open my $outfh, '>', 'outfile.csv' or die "Failed to open outfile.csv: $!";
for my $id (sort keys %data) {
my @merge_data;
for my $i (0 .. $#input_files) {
push @merge_data, $data{$id}[$i] || '0,0,0';
}
print $outfh join(',', @merge_data) . "\n";
}
第一个循环将每个文件的所有行收集到数组的散列中。散列键是ID,因此所有文件中该ID的行保持在一起,每个键的值是(引用)与每个文件中该ID相关联的行的数组;使用数组可以让我们跟踪缺失的值以及存在的值。
然后第二个循环获取该散列的键(按字母顺序),并为每个循环创建一个与该ID相关联的值的临时数组,用“0,0,0”代替缺失值,将它们连接起来单个字符串,并将其打印到输出文件。
outfile.csv
中的结果是:
IPR000531,TonB receptor,150,0,0,0,0,0,0
0,0,0,IPR000873,AMP-dependent synthetase/ligase,111,0,0,0
IPR003594,ATPase,179,0,0,0,IPR003594,ATPase,158
0,0,0,IPR011991,Winged,113,0,0,0
IPR013785,Aldolase,304,IPR013785,Aldolase,300,IPR013785,Aldolase,367
IPR014729,Rossmann,327,IPR014729,Rossmann,261,IPR014729,Rossmann,338
IPR015421,Pyridoxal,224,IPR015421,Pyridoxal,189,IPR015421,Pyridoxal,271
IPR017690,Outer membrane, omp85 target,821,IPR017690,Outer membrane, omp85 target,728,IPR017690,Outer membrane,905
IPR018248,EF-hand,10,0,0,0,IPR018248,EF-hand,3
编辑:在评论中添加了OP要求的解释
你可以告诉我我的$ id =(split',',$ _,2)[0]的工作;和$#在这个程序中
my $id = (split ',', $_, 2)[0];
获取读取的最后一行文本中第一个逗号之前的文本:
while (<$infh>)
会将其读入默认变量$_
。split ',', $_, 2
将$_
的值拆分为逗号分隔字段列表。最后的2
告诉它最多只产生2个字段;代码在没有2
的情况下工作正常,但是,因为我只需要第一个字段,所以不需要分割成更多的部分。(...)[0]
命令周围放置split
会将返回的字段列表转换为(匿名)数组,并返回该数组的第一个元素。这就像我写my @fields = split ',', $_, 2; my $id = $fields[0];
一样,但更短,没有额外的变量。 $#array
返回数组@array
中编号最大的索引,因此for my $i (0 .. $#array)
仅表示“遍历@array
中所有元素的索引”。 (注意,如果我不需要索引计数器的值,我会使用for my $filename (@input_files)
直接循环遍历数组的数据,但是跟踪缺失的值会不太方便如果我这样做的话。)