![根据匹配字段对列进行求和](https://linux22.com/image/5298/%E6%A0%B9%E6%8D%AE%E5%8C%B9%E9%85%8D%E5%AD%97%E6%AE%B5%E5%AF%B9%E5%88%97%E8%BF%9B%E8%A1%8C%E6%B1%82%E5%92%8C.png)
我有一个以下格式的大文件:
2 1019 0 12
2 1019 3 0
2 1021 0 2
2 1021 2 0
2 1022 4 5
2 1030 0 1
2 1030 5 0
2 1031 4 4
如果值在第2栏匹配,我想对其中的值求和第3栏和4两行的值,否则只是唯一行中值的总和。
所以我希望的输出如下所示:
2 1019 15
2 1021 4
2 1022 9
2 1030 6
2 1031 8
我能够根据以下条件对文件进行排序第2栏使用awk
或sort
并对最后一列求和awk
,但仅适用于单行,不适用于两行,其中第2栏火柴。
答案1
我会在 Perl 中这样做:
$ perl -lane '$k{"$F[0] $F[1]"}+=$F[2]+$F[3];
END{print "$_ $k{$_}" for keys(%k) }' file
2 1019 15
2 1021 4
2 1030 6
2 1031 8
2 1022 9
或者 awk:
awk '{a[$1" "$2]+=$3+$4}END{for (i in a){print i,a[i]}}' file
如果您希望根据第二列对输出进行排序,您可以通过管道传输到sort
:
awk '{a[$1" "$2]+=$3+$4}END{for (i in a){print i,a[i]}}' file | sort -k2
请注意,两个解决方案都包含第一列。这个想法是使用第一列和第二列作为哈希(在 perl 中)或关联数组(在 awk 中)的键。每个解决方案的关键是column1 column2
,如果两行具有相同的第二列但不同的第一列,它们将被单独分组:
$ cat file
2 1019 2 3
2 1019 4 1
3 1019 2 2
$ awk '{a[$1" "$2]+=$3+$4}END{for (i in a){print i,a[i]}}' file
3 1019 4
2 1019 10
答案2
也许这会有所帮助,但是第 1 列是否始终为 2,结果是否取决于它?
awk '{ map[$2] += $3 + $4; } END { for (i in map) { print "2", i, map[i] | "sort -t't'" } }' file
或如所提到的格伦·杰克曼关于排序的评论:
gawk '{ map[$2] += $3 + $4; } END { PROCINFO["sorted_in"] = "@ind_str_asc"; for (i in map) { print 2, i, map[i] } }' file
答案3
您可以对数据进行预排序并让 awk 处理详细信息:
sort -n infile | awk 'NR>1 && p!=$2 {print p,s} {s+=$3+$4} {p=$2}'
您可能需要重置累加器:
sort -n infile | awk 'NR>1 && p!=$2 {print p,s;s=0} {s+=$3+$4} {p=$2}'
输出:
1019 15
1021 19
1022 28
1030 34
如果您确实想要保留第一列,请执行以下操作:
sort -n infile | awk 'NR>1 && p!=$1FS$2 {print p,s} {s+=$3+$4} {p=$1FS$2}'
输出:
2 1019 15
2 1021 19
2 1022 28
2 1030 34
解释
该p
变量保存$2
前一行的值,或者$1FS$2
在上面的第二种情况下。这意味着当前一行与当前行不同时{print p,s}
触发( )。$2
p!=$2
答案4
使用瑞士军刀utilmlr
:
mlr --nidx put '$5=$3+$4' then stats1 -g 1,2 -f 5 -a sum infile
输出:
2 1019 15
2 1021 4
2 1022 9
2 1030 6
2 1031 8
笔记:
--nidx
告诉mlr
使用数字字段名称。put '$5=$3+$4'
创造一个新的第五名字段、字段之和3和4。函数
stats1
(或“动词
") 是较大瑞士军刀中较小的瑞士军刀mlr
,具有多种基于累加器的功能,例如sum
,count
,mean
,ETC。stats1 -g 1,2
按列对数据进行分组1和2,-f 5 -a sum
然后将这些组的字段相加5。stats1
仅打印命名字段。