awk 计算唯一出现次数并打印其他列
awk count unique occurrences and print other columns
我有如下一段代码:
awk '{h[]++}; END { for(k in h) print k, h[k]}' ${infile} >> ${outfile2}
这是我想要的一部分:打印出唯一值,然后计算这些唯一值出现的次数。现在,我还想从每个唯一值中打印出第 2 列和第 3 列。由于某种原因,以下内容似乎不起作用:
awk '{h[]++}; END { for(k in h) print k, , , h[k]}' ${infile} >> ${outfile2}
awk '{h[]++}; END { for(k in h) print k, h[], h[], h[k]}' ${infile} >> ${outfile2}
第一个打印出最后一个索引的第 2 和第 3 列,而第二个代码打印出除了 k 和 h[k] 之外的任何内容。
${infile} 看起来像:
20600 33.8318 -111.9286 -1 0.00 0
20600 33.8318 -111.9286 -1 0.00 0
30900 33.3979 -111.8140 -1 0.00 0
29400 33.9455 -113.5430 -1 0.00 0
30600 33.4461 -111.7876 -1 0.00 0
20600 33.8318 -111.9286 -1 0.00 0
30900 33.3979 -111.8140 -1 0.00 0
30600 33.4461 -111.7876 -1 0.00 0
所需的输出将是:
20600, 33.8318, -111.9286, 3
30900, 33.3979, -111.8140, 2
29400, 33.9455, -113.5430, 1
30600, 33.4461, -111.7876, 2
GNU datamash 是一个非常方便的工具,用于处理文件中的柱状数据组,使这项工作变得微不足道。
假设您的文件使用制表符分隔各列,就像它看起来的那样:
$ datamash -s --output-delimiter=, -g 1,2,3 count 3 < input.tsv
20600,33.8318,-111.9286,3
29400,33.9455,-113.5430,1
30600,33.4461,-111.7876,2
30900,33.3979,-111.8140,2
虽然在awk中并没有复杂多少,但是使用多维数组:
$ awk 'BEGIN { OFS=SUBSEP="," }
{ group[,,]++ }
END { for (g in group) print g, group[g] }' input.tsv
29400,33.9455,-113.5430,1
30600,33.4461,-111.7876,2
20600,33.8318,-111.9286,3
30900,33.3979,-111.8140,2
如果你想要排序输出而不是随机顺序,如果使用 GNU awk,请在 BEGIN
块中添加一个 PROCINFO["sorted_in"] = "@ind_str_asc"
,或者通过 sort
管道输出.
您也可以通过流水线化一堆实用程序(包括 awk 和 uniq)来获得相同的效果:
$ sort -k1,3n input.tsv | cut -f1-3 | uniq -c | awk -v OFS=, '{ print , , , }'
20600,33.8318,-111.9286,3
29400,33.9455,-113.5430,1
30600,33.4461,-111.7876,2
30900,33.3979,-111.8140,2
你很接近,你可以在 awk
中完成所有操作,但如果你要存储基于字段 1 的计数,并且在 END
中还可以使用字段 2 和字段 3输出,您还需要将字段 2 和 3 存储在由字段 1(或您正在计算的任何字段)索引的数组中。例如你可以这样做:
awk -v OFS=', ' '
{ h[]++; i[]=; j[]= }
END {
for (a in h)
print a, i[a], j[a], h[a]
}
' infile
其中 h[]
保存字段 1 被视为索引数组与字段 1 的次数计数。i[]=
捕获由字段 1 索引的字段 2,然后 j[]=
捕获由字段 1 索引的字段 3。
然后在END
内只需要输出字段1(a
h
的索引),i[a]
(字段2),j[a]
(字段 3),最后 h[a]
看到字段 1 的次数。
例子Use/Output
使用您的示例数据,您可以 copy/middle-mouse-paste 终端上的代码使用正确的文件名,例如
$ awk -v OFS=', ' '
> { h[]++; i[]=; j[]= }
> END {
> for (a in h)
> print a, i[a], j[a], h[a]
> }
> ' infile
20600, 33.8318, -111.9286, 3
29400, 33.9455, -113.5430, 1
30600, 33.4461, -111.7876, 2
30900, 33.3979, -111.8140, 2
它提供了所需的输出。如果您需要按照您显示的输出顺序保留记录的顺序,您可以使用字符串连接将字段 1、2 和 3 分组为数组的索引,然后输出数组和索引,例如
$ awk '{a[", "", "]++}END{for(i in a) print i ", " a[i]}' infile
20600, 33.8318, -111.9286, 3
30600, 33.4461, -111.7876, 2
29400, 33.9455, -113.5430, 1
30900, 33.3979, -111.8140, 2
检查一下,如果您还有其他问题,请告诉我。
我有如下一段代码:
awk '{h[]++}; END { for(k in h) print k, h[k]}' ${infile} >> ${outfile2}
这是我想要的一部分:打印出唯一值,然后计算这些唯一值出现的次数。现在,我还想从每个唯一值中打印出第 2 列和第 3 列。由于某种原因,以下内容似乎不起作用:
awk '{h[]++}; END { for(k in h) print k, , , h[k]}' ${infile} >> ${outfile2}
awk '{h[]++}; END { for(k in h) print k, h[], h[], h[k]}' ${infile} >> ${outfile2}
第一个打印出最后一个索引的第 2 和第 3 列,而第二个代码打印出除了 k 和 h[k] 之外的任何内容。
${infile} 看起来像:
20600 33.8318 -111.9286 -1 0.00 0
20600 33.8318 -111.9286 -1 0.00 0
30900 33.3979 -111.8140 -1 0.00 0
29400 33.9455 -113.5430 -1 0.00 0
30600 33.4461 -111.7876 -1 0.00 0
20600 33.8318 -111.9286 -1 0.00 0
30900 33.3979 -111.8140 -1 0.00 0
30600 33.4461 -111.7876 -1 0.00 0
所需的输出将是:
20600, 33.8318, -111.9286, 3
30900, 33.3979, -111.8140, 2
29400, 33.9455, -113.5430, 1
30600, 33.4461, -111.7876, 2
GNU datamash 是一个非常方便的工具,用于处理文件中的柱状数据组,使这项工作变得微不足道。
假设您的文件使用制表符分隔各列,就像它看起来的那样:
$ datamash -s --output-delimiter=, -g 1,2,3 count 3 < input.tsv
20600,33.8318,-111.9286,3
29400,33.9455,-113.5430,1
30600,33.4461,-111.7876,2
30900,33.3979,-111.8140,2
虽然在awk中并没有复杂多少,但是使用多维数组:
$ awk 'BEGIN { OFS=SUBSEP="," }
{ group[,,]++ }
END { for (g in group) print g, group[g] }' input.tsv
29400,33.9455,-113.5430,1
30600,33.4461,-111.7876,2
20600,33.8318,-111.9286,3
30900,33.3979,-111.8140,2
如果你想要排序输出而不是随机顺序,如果使用 GNU awk,请在 BEGIN
块中添加一个 PROCINFO["sorted_in"] = "@ind_str_asc"
,或者通过 sort
管道输出.
您也可以通过流水线化一堆实用程序(包括 awk 和 uniq)来获得相同的效果:
$ sort -k1,3n input.tsv | cut -f1-3 | uniq -c | awk -v OFS=, '{ print , , , }'
20600,33.8318,-111.9286,3
29400,33.9455,-113.5430,1
30600,33.4461,-111.7876,2
30900,33.3979,-111.8140,2
你很接近,你可以在 awk
中完成所有操作,但如果你要存储基于字段 1 的计数,并且在 END
中还可以使用字段 2 和字段 3输出,您还需要将字段 2 和 3 存储在由字段 1(或您正在计算的任何字段)索引的数组中。例如你可以这样做:
awk -v OFS=', ' '
{ h[]++; i[]=; j[]= }
END {
for (a in h)
print a, i[a], j[a], h[a]
}
' infile
其中 h[]
保存字段 1 被视为索引数组与字段 1 的次数计数。i[]=
捕获由字段 1 索引的字段 2,然后 j[]=
捕获由字段 1 索引的字段 3。
然后在END
内只需要输出字段1(a
h
的索引),i[a]
(字段2),j[a]
(字段 3),最后 h[a]
看到字段 1 的次数。
例子Use/Output
使用您的示例数据,您可以 copy/middle-mouse-paste 终端上的代码使用正确的文件名,例如
$ awk -v OFS=', ' '
> { h[]++; i[]=; j[]= }
> END {
> for (a in h)
> print a, i[a], j[a], h[a]
> }
> ' infile
20600, 33.8318, -111.9286, 3
29400, 33.9455, -113.5430, 1
30600, 33.4461, -111.7876, 2
30900, 33.3979, -111.8140, 2
它提供了所需的输出。如果您需要按照您显示的输出顺序保留记录的顺序,您可以使用字符串连接将字段 1、2 和 3 分组为数组的索引,然后输出数组和索引,例如
$ awk '{a[", "", "]++}END{for(i in a) print i ", " a[i]}' infile
20600, 33.8318, -111.9286, 3
30600, 33.4461, -111.7876, 2
29400, 33.9455, -113.5430, 1
30900, 33.3979, -111.8140, 2
检查一下,如果您还有其他问题,请告诉我。