2015-04-01 62 views
4

我的csv文件中的第二列有重复项。我想根据这些重复添加第1列的相关值。Bash - 根据列在行中添加值

例CSV:

56, cc=DK 
49, cc=US 
34, cc=GB 
32, cc=DE 
32, cc=NZ 
31, cc=DK 
31, cc=GB 
31, cc=GB 

结果举例:

96, cc=GB # where 96 = 34+31+31 
87, cc=DK # where 87 = 56+31 
32, cc=DE 
32, cc=NZ 
+1

'awk -F,'{a [$ 2] + = $ 1} END {for(i in a)print a [i] FS i}'file'。你也离开了美国的输出 – 2015-04-01 08:02:40

回答

2

可以在awk使用关联数组:

awk '{s[$2]+=$1}END{for(k in s)print s[k]", ",k}' inFile 

拓展上,对于可读性,使用sum/key,而不是s/k

{         # Do for each line. 
    sum[$2] += $1     # Add first field to accumulator, 
            # indexed by second field. 
            # initial value is zero. 
} 
END {        # Do this bit when whole file processed. 
    for (key in sum)    # For each key like cc=US: 
     print sum[key] ", " key # Output the sum and key. 
} 

这里有我的盒子样品运行:

pax$ echo;echo '56, cc=DK 
49, cc=US 
34, cc=GB 
32, cc=DE 
32, cc=NZ 
31, cc=DK 
31, cc=GB 
31, cc=GB' | awk '{s[$2]+=$1}END{for(k in s)print s[k]", "k}' 

32, cc=DE 
96, cc=GB 
32, cc=NZ 
49, cc=US 
87, cc=DK 

这工作尽管第一列的形式999,的(注意最后的逗号),只是因为awk,当在数字上下文中计算字符串,只使用在该上下文中有效的前缀。因此45xyzzy将变成45,更重要的是,49,变成49

+0

你也可以改变FS而不是gsub(这是没有意义的,因为你正在改变'',并且可以使用sub,因为它是$ 1,因为它默认为$ 0)根据我的代码对这个问题的评论。 – 2015-04-01 08:13:02

+0

@JID,我确实想到了,但事实证明gsub/sub甚至不需要,所以我删除了它。 – paxdiablo 2015-04-01 08:26:23

+1

哦,是的,你可以削减2个字符,因为不需要'(k in s)'之后的'{}'。 – 2015-04-01 08:27:45

1

Perl的溶液:

perl -ane '$h{ $F[1] } += $F[0] }{ print "$h{$_}\t$_\n" for keys %h' input.csv 

说明:

  • -n处理由线
  • -a输入线按空白进行分割输入线到@F阵列
  • 中的字段哈希表%h记录每个键的总和(2 nd列)。它只是将第一列的值添加到它。
  • }{(称为“爱斯基摩人的问候语”)分开什么是从每行代码(-n)执行整个输入被处理
0

这是确定使用awk这种简单的任务后运行,但如果你有很多类似的任务,你可能需要在将来改变它,很容易搞砸了。

由于这是典型的数据库问题,请考虑使用sqlite

您可以:

  1. 添加行名称和删除多余的空格:

    $ cat <(echo "num, name") originalInput.txt | tr -d ' ' > input.csv 
    
  2. 导入数据到临时的SQLite数据库:从数据库

    $ sqlite3 --batch temp.db <<EOF! 
    .mode csv 
    .import input.csv input 
    EOF! 
    
  3. 选择:

    $sqlite3 temp.db 'SELECT sum(num), name FROM input GROUP BY name' 
    32|cc=DE 
    87|cc=DK 
    96|cc=GB 
    32|cc=NZ 
    49|cc=US 
    

它稍微多一点的代码,并使用外部sqlite3命令,但它是显著不容易出错灵活。你可以很容易地加入几个CSV文件,使用奇特的排序,等等。

此外,假设你自己在六个月后查看代码,试图快速了解它的功能。

+1

您的最后一条陈述取决于您对该语言的熟悉程度,需要更长的时间才能确定您的代码与上面的awk相比有多长。这只是看起来像是过度杀伤。不但你必须安装一个外部程序(每个人都可能因为某种原因无法完成)你还必须编辑原始数据,创建一个数据库,然后得到输出不再以CSV格式。如果你想要比awk更强大的方法,你可以使用一个csv解析器。 – 2015-04-01 09:32:23

+0

@JID,“可以使用awk,在这里,但*如果你有一堆类似的任务,请考虑* sqlite”。我在制作中看到过数百个这样的awk/sed/perl/* sh脚本,并且在很多情况下,它并不适合这项工作。顺便说一句,csv解析器不会为你做聚合。 – 2015-04-01 10:38:43

+1

我也见过很多'魔术awk/sed/perl/* sh脚本',如果它们没有被写得很糟糕,并且你对这门语言有一个基本的理解,那么你就不会立即理解正在做什么。另外我的意思是在python或perl中使用csv解析器,阅读它可能应该已经更清楚了。 – 2015-04-01 11:06:12