代码之家  ›  专栏  ›  技术社区  ›  Alper Yilmaz

在Awk中从多维数组的子数组中获取最小值和最大值

  •  0
  • Alper Yilmaz  · 技术社区  · 4 年前

    我有数百万行不同日期的城市测量数据。有多个测量,所以我需要 得到最小值和最大值 针对每个城市和日期组合。 以下是示例数据:

    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"} 但没用。

    0 回复  |  直到 4 年前
        1
  •  2
  •   anubhava    4 年前

    不需要进行排序。

    使用 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
    
        2
  •  1
  •   Ed Morton    4 年前

    关于 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表示数组和 你进来了吗 .

    如果这个问题不是关于数组排序的,那么我会通过管道来解决 sort -k1,2 -k3,3n file 变成一个awk脚本,每1美元/2美元的组合只打印第一个和最后一个3美元。