我想使用perl按特定条件合并多个csv文件

时间:2013-04-01 11:35:15

标签: perl csv

我有多个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

有谁知道我该怎么做? 谢谢你的帮助

1 个答案:

答案 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)直接循环遍历数组的数据,但是跟踪缺失的值会不太方便如果我这样做的话。)

相关问题