从Awk中的多维数组中的子数组获取最小值和最大值
Posted
技术标签:
【中文标题】从Awk中的多维数组中的子数组获取最小值和最大值【英文标题】:get min and max from subarray in multidimensional array in Awk 【发布时间】:2021-07-30 04:45:37 【问题描述】:我有数百万行不同日期的城市测量数据。有多个测量值,因此我需要为每个城市和日期组合获取最小值和最大值。 这是示例数据:
London Wednesday 19
Melbourne Tuesday 128
London Wednesday 9
London Tuesday 9
Melbourne Tuesday 99
London Wednesday 18
London Tuesday 2
Melbourne Wednesday 89
Melbourne Wednesday 9
Melbourne Tuesday 23
London Tuesday 13
Melbourne Wednesday 11
我试过了
arr[$1][$2][$3]++
END
for (city in arr)
printf"%s\t",city
for (day in arr[city])
n=asorti(arr[city][day],sorted)
printf"%s\t%s\t%s\t",day,sorted[1],sorted[n];
printf"\n"
但我得到的是字母顺序而不是数字顺序:
Melbourne Tuesday 128 99 Wednesday 11 9
London Tuesday 13 9 Wednesday 18 9
我需要的是:
Melbourne Tuesday 23 128 Wednesday 9 89
London Tuesday 2 13 Wednesday 9 19
我尝试使用BEGIN PROCINFO["sorted_in"] = "@ind_num_asc"
,但没有帮助。
【问题讨论】:
【参考方案1】:不需要排序。
使用gnu-awk
,你可以使用这个:
awk 'max[$1][$2] < $3 max[$1][$2] = $3 !min[$1][$2] || min[$1][$2] > $3 min[$1][$2] = $3 END for (i in max) printf "%s", i; for (j in max[i]) printf " %s %d %d", j, min[i][j], max[i][j]; print ""' file | column -t
Melbourne Tuesday 23 128 Wednesday 9 89
London Tuesday 2 13 Wednesday 9 19
可读版本:
awk '
max[$1][$2] < $3
max[$1][$2] = $3
!min[$1][$2] || min[$1][$2] > $3
min[$1][$2] = $3
END
for (i in max)
printf "%s", i
for (j in max[i])
printf " %s %d %d", j, min[i][j], max[i][j]
print ""
' file | column -t
【讨论】:
与专栏的好接触! 非常感谢。我在asorti()
上花了几个小时,看来我必须更改数据结构。我已经接受了答案,但我仍然对基于 asorti()
的解决方案感兴趣。我正在使用大量多维数组,当我需要在某个子数组级别执行 smt 时,我陷入了困境。如果您能提供有关数组排序解决方案的提示或解决方案,我将不胜感激。再次感谢..【参考方案2】:
关于I'm getting alphabetical order not numerical order
- 对,因为数组索引总是字符串,即使它们看起来像数字,所以asorti()
默认情况下会进行字符串/字母排序。如果您希望它进行数字排序,那么您必须通过添加一个额外的参数asorti(arr[city][day],sorted,"@ind_num_asc")
来告诉它,请参阅https://www.gnu.org/software/gawk/manual/gawk.html#Array-Sorting-Functions。
我不会为此(或大多数事情)打扰asorti()
,不过,只需使用sorted_in
:
$ cat tst.awk
vals[$1][$2][$3]
END
PROCINFO["sorted_in"] = "@ind_num_asc"
for ( city in vals )
printf "%s", city
for ( day in vals[city] )
printf "%s%s", OFS, day
cnt = 0
for ( val in vals[city][day] )
if ( ++cnt == 1 )
min = val
max = val
printf "%s%s%s%s", OFS, min, OFS, max
print ""
$ awk -f tst.awk file | column -t
London Tuesday 2 13 Wednesday 9 19
Melbourne Tuesday 23 128 Wednesday 9 89
上面使用 GNU awk 处理数组和 sorted_in
。
如果这个问题不是专门关于排序数组的,那么我会通过将sort -k1,2 -k3,3n file
管道化到一个 awk 脚本中来完成,该脚本只打印每个 $1/$2 组合的第一个和最后一个 $3。
【讨论】:
感谢您的详细解释.. 看起来asorti()
在专业 awk 用户中不受欢迎;)
不客气。我只是不确定asorti()
或asort()
的用例是什么,因为sorted_in
存在。如果您必须以相同的顺序多次循环遍历一个数组,也许会有一些效率考虑,或者您可能有一个只需要一个数字索引数组的函数,所以您需要从现有数组创建一个?以上是关于从Awk中的多维数组中的子数组获取最小值和最大值的主要内容,如果未能解决你的问题,请参考以下文章
从具有 O(n) 的数组中获取最大的时间下降、最小值和最大值
从 p5.js 的 JSON 文件中的数组中查找最小值和最大值