从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 文件中的数组中查找最小值和最大值

java程序,随机产生包含20个元素的数组,求出数组中的最大值,最小值和平均值

Pyspark - 从具有最小值和最大值范围的数组中获取值

js获取数组中的最大值最小值

数组中的 Java 最小值和最大值