Linux 如何基于第一个字段合并csv文件中的记录?

Linux 如何基于第一个字段合并csv文件中的记录?,linux,perl,csv,merge,perlscript,Linux,Perl,Csv,Merge,Perlscript,我有一个csv文件 id1,v1,v2,v3,v4 id2,v1,v2,v6,v4 id1,v7,v8,v3,v9 id1,v10,v11,v12,v13 id2,v3,v5,v8,v7 因为,该文件未排序,因此不应! 我希望输出为: id1,v1|v7|v10,v2|v8|v11,v3|v12,v4|v9|v13 id2,v1|v10,v2|v5,v6|v8,v4|v7 其中,列中的所有相应值合并到记录中具有相同id的相应列中,但重复值(参见第3列中v3的id1)和id除外

我有一个csv文件

 id1,v1,v2,v3,v4
 id2,v1,v2,v6,v4
 id1,v7,v8,v3,v9
 id1,v10,v11,v12,v13
 id2,v3,v5,v8,v7
因为,该文件未排序,因此不应! 我希望输出为:

 id1,v1|v7|v10,v2|v8|v11,v3|v12,v4|v9|v13
 id2,v1|v10,v2|v5,v6|v8,v4|v7
其中,列中的所有相应值合并到记录中具有相同id的相应列中,但重复值(参见第3列中v3的id1)和id除外

我用这里给出的代码试过了。但它需要的远不止这些


如何使用perl实现这一点?我是perl新手。提前谢谢

假设不需要任何特定的排序顺序,可以使用数组哈希来解决此问题。哈希在其他语言中被称为字典

use strict;
use warnings;

my %data;

while ( <DATA> ) {
  my ($id, @vals) = /[^,\s]+/g;
  for my $i ( 0 .. $#vals ) {
    ++$data{$id}[$i]{$vals[$i]};
  }
}

while ( my ($id, $vals) = each %data ) {
  my @vals = map { join '|', keys %$_ } @$vals;
  printf "%s,%s\n", $id, join ',', @vals;
}

__DATA__
id1,v1,v2,v3,v4
id2,v1,v2,v6,v4
id1,v7,v8,v3,v9
id1,v10,v11,v12,v13
id2,v3,v5,v8,v7

您应该为CSV数据使用适当的CSV解析器

use strict;
use warnings;
use Text::CSV;

my $csv = Text::CSV->new( { binary => 1, eol => $/ } );

my %data;
while ( my $row = $csv->getline(*DATA) ) {
    my $id = shift @$row;
    $data{$id}[$_]{ $$row[$_] } = undef for 0 .. $#$row;
}

for my $id ( sort keys %data ) {
    my $vals = $data{$id};
    $csv->print( \*STDOUT, [ $id, map { join '|', sort keys %$_ } @$vals ] );
}

__DATA__
id1,v1,v2,v3,v4
id2,v1,v2,v6,v4
id1,v7,v8,v3,v9
id1,v10,v11,v12,v13
id2,v3,v5,v8,v7

我很抱歉:我最初的解决方案是错误的,因为我误解了你的问题。现在就应该开始了非常感谢@Borodin,它的完美ans。我刚刚删除了printf中的$fh,并添加了“open(DATA,$fh,我很抱歉-这是我测试的遗留问题。管道分隔的复合字段是否需要按照它们在文件中出现的顺序排列?例如,
id1,v10 | v1 | v7,…
可以吗?@Borodin,很抱歉回复晚了,顺序不重要。
use strict;
use warnings;
use Text::CSV;

my $csv = Text::CSV->new( { binary => 1, eol => $/ } );

my %data;
while ( my $row = $csv->getline(*DATA) ) {
    my $id = shift @$row;
    $data{$id}[$_]{ $$row[$_] } = undef for 0 .. $#$row;
}

for my $id ( sort keys %data ) {
    my $vals = $data{$id};
    $csv->print( \*STDOUT, [ $id, map { join '|', sort keys %$_ } @$vals ] );
}

__DATA__
id1,v1,v2,v3,v4
id2,v1,v2,v6,v4
id1,v7,v8,v3,v9
id1,v10,v11,v12,v13
id2,v3,v5,v8,v7