【问题标题】:How to merge records in csv file based on first field?如何根据第一个字段合并csv文件中的记录?
【发布时间】:2015-05-23 21:46:27
【问题描述】:

我有一个 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 的记录中的相应列,除了重复值(id1 见第 3 列中的 v3)和 id。

我使用此处给出的代码http://www.robelle.com/tips/st-export-notes.html 进行了尝试。但它需要的远不止这些。

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

【问题讨论】:

  • 管道分隔的复合字段是否必须按照它们在文件中出现的顺序排列?例如,id1,v10|v1|v7,... 好吗?
  • @Borodin,抱歉回复晚了,顺序不重要。

标签: linux perl csv merge perlscript


【解决方案1】:

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

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

输出

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

【讨论】:

  • 对不起:我原来的解决方案是错误的,因为我误读了你的问题。应该是现在
  • 非常感谢@Borodin,它的完美答案。我刚刚在 printf 中删除了 $fh,并添加了 'open(DATA, "
  • @NTN:我很乐意提供帮助。对于无关紧要的$fh,我深表歉意——这是我的测试遗留下来的。
【解决方案2】:

您应该对 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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-06-20
    • 1970-01-01
    • 2014-06-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-12-29
    相关资源
    最近更新 更多