【问题标题】:get min and max from subarray in multidimensional array in Awk从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"},但没有帮助。

【问题讨论】:

    标签: arrays awk


    【解决方案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 存在。如果您必须以相同的顺序多次循环遍历一个数组,也许会有一些效率考虑,或者您可能有一个只需要一个数字索引数组的函数,所以您需要从现有数组创建一个?
    猜你喜欢
    • 2011-05-28
    • 2017-11-03
    • 2021-12-03
    • 2014-05-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-18
    相关资源
    最近更新 更多