删除重复项并使用linux在csv文件中根据时间戳获取最新数据

时间:2014-11-17 14:59:42

标签: linux sorting unix csv awk

我有一个巨大的csv文件(100,000条记录),其中包含如下数据:

Col1  Col2       Date & Time 
a     xyz      Oct 31 2014 09:01 
b     xyz      Dec 12 2013 08:15 
a     xyz      Oct 30 2014 07:01 
c     xyz      Dec 26 2013 08:39 
a     xyz      Nov 12 2014 08:25 
c     xyz      Dec 12 2013 08:10 
b     xyz      Dec 12 2013 09:21 

我需要删除重复项并仅保留最新的数据(基于第三列 - 日期和时间)。所以输出应该像

 Col1    Col2        Date & Time 
    a     xyz      Nov 12 2014 08:25 
    b     xyz      Dec 12 2013 09:21
    c     xyz      Dec 26 2013 08:39 

我首先尝试对文件进行排序,然后删除重复项,但是这个巨大的csv文件失败了。有人可以帮忙吗?

P.S。在col1中,数据可以多次来自a-z。这只是一个样本。

2 个答案:

答案 0 :(得分:0)

让我们尝试一下:

while IFS="," read -r a b c
do
  printf "%s %s %s %d\n" "$a" "$b" "$c" $(date -d"$c" +"%s")
done < file | \
awk '{it=$NF; NF--
      if (max[$1]<it) {max[$1]=it; res[$1]=$0}}
        END {for (i in max) print res[i]}'

这将存储数组max[]中的最大日期,该数据由临时的最后一个字段索引,该字段表示自1970年1月1日以来的秒数(先前使用while read bash创建的)。处理整个块后,在END{}中打印结果。

它返回:

a xyz Nov 12 2014 08:25
b xyz Dec 12 2013 09:21
c xyz Dec 26 2013 08:39

如果碰巧以逗号分隔,请使用:

$ while IFS="," read -r a b c; do printf "%s,%s,%s,%d\n" "$a" "$b" "$c" $(date -d"$c" +"%s"); done < a | awk 'BEGIN{FS=OFS=","} {it=$NF; NF--
          if (max[$1]<it) {max[$1]=it; res[$1]=$0}}
            END {for (i in max) print res[i]}'
a,xyz,Nov 12 2014 08:25
b,xyz,Dec 12 2013 09:21
c,xyz,Dec 26 2013 08:39

答案 1 :(得分:0)

您的流程有3个步骤。 第一:

  • 提取关键字段。 (我用perl和split)。

  • 将日期解析为数字格式。你可以做某种ISO风格,例如2014-12-26 08:39或将其变成Unix'时代'时代。 (如果它是CSV,如果你真的想要,你可能会通过Excel进行处理。)

  • 运行您的输入,丢弃任何“旧”值。

所以考虑到这一点 - 假设因为你说'CSV',你的意思是它实际上是逗号分隔的值。

#!/usr/bin/perl

use strict;
use warnings;

use Time::Piece;

my %most_recent;

my $header = <DATA>;

while ( my $line = <DATA> ) {
    chomp $line;
    my ( $col1, $col2, $date_and_time ) = split( /,\s*/, $line, 3 );
    $date_and_time =~ s/\s+$//g;

    my $time = Time::Piece ->  new -> strptime( $date_and_time, "%b %d %Y %H:%M" );

    if ( not defined $most_recent{$col1}{$col2}
        or $most_recent{$col1}{$col2} < $time )
    {
        $most_recent{$col1}{$col2} = $time;
    }
}

print "Most recent:\n";
foreach my $col1 ( keys %most_recent ) {
    foreach my $col2 ( keys %{ $most_recent{$col1} } ) {
        print "$col1, $col2, $most_recent{$col1}{$col2}, \n";
    }
}


__DATA__
Col1, Col2,       Date & Time 
a, xyz,      Oct 31 2014 09:01 
b, xyz,      Dec 12 2013 08:15 
a, xyz,      Oct 30 2014 07:01 
c, xyz,      Dec 26 2013 08:39 
a,     xyz,      Nov 12 2014 08:25 
c,     xyz,      Dec 12 2013 08:10 
b,     xyz,      Dec 12 2013 09:21 

这将 - 对于Col1Col2的每个唯一配对,选择该对的最新时间戳。

注意 - 在各个步骤(拆分和时间戳解析)中,空格被丢弃。