Bash awk排序多维数组

Bash awk排序多维数组,bash,awk,gawk,Bash,Awk,Gawk,GNU awk支持: 我想对q中的“第二列”进行排序,以便留下: q[1][1] = "mouse" q[1][2] = 777 q[2][1] = "bird" q[2][2] = 888 q[3][1] = "dog" q[3][2] = 999 正如您所看到的,“第一列”值被移动以与第二列保持一致。我懂了 GNU Awk提供了一个新的解决方案,但它似乎不支持 多维数组。如果有帮助的话,这是一个 : 我最终使用了一个常规数组,然后用换行符分隔重复项: q[777] = "mouse" q[

GNU awk支持:

我想对
q
中的“第二列”进行排序,以便留下:

q[1][1] = "mouse"
q[1][2] = 777
q[2][1] = "bird"
q[2][2] = 888
q[3][1] = "dog"
q[3][2] = 999
正如您所看到的,“第一列”值被移动以与第二列保持一致。我懂了 GNU Awk提供了一个新的解决方案,但它似乎不支持 多维数组。如果有帮助的话,这是一个 :

我最终使用了一个常规数组,然后用换行符分隔重复项:

q[777] = "mouse"
q[999] = "dog" RS "fish"
q[888] = "bird"
for (z in q) {
  print q[z]
}
支持真正的多维数组

不,没有。它支持数组的数组,并支持由两个索引合并在一起的字符串索引的哈希。您的语法是前者(数组的数组)

也就是说,我不认为您可以使用内置函数来实现,因为它要么需要使用比较器回调,要么需要能够返回排序排列,当然这两者都不是
gawk
提供的

但是您可以参考其中描述如何为自己实现qsort的部分,在这里您可以将比较从
A[i]
更改为
A[i][2]
FWIW,这里是一个解决方法“sort\u by()”函数:

$ cat tst.awk
BEGIN {
    a[1][1] = "dog"
    a[1][2] = 999
    a[2][1] = "mouse"
    a[2][2] = 777
    a[3][1] = "bird"
    a[3][2] = 888

    print "\n############################\nBefore:"
    for (i=1; i in a; i++)
        for (j=1; j in a[i]; j++)
            printf "a[%d][%d] = %s\n",i,j,a[i][j]
    print "############################"

    sort_by(a,2)

    print "\n############################\nAfter:"
    for (i=1; i in a; i++)
        for (j=1; j in a[i]; j++)
            printf "a[%d][%d] = %s\n",i,j,a[i][j]
    print "############################"

}

function sort_by(arr,key,       keys,vals,i,j)
{
    for (i=1; i in arr; i++) {
        keys[i] = arr[i][key]
        for (j=1; j in arr[i]; j++)
            vals[keys[i]] = vals[keys[i]] (j==1?"":SUBSEP) arr[i][j]
    }

    asort(keys)

    for (i=1; i in keys; i++)
       split(vals[keys[i]],arr[i],SUBSEP)

    return (i - 1)
}

$ gawk -f tst.awk

############################
Before:
a[1][1] = dog
a[1][2] = 999
a[2][1] = mouse
a[2][2] = 777
a[3][1] = bird
a[3][2] = 888
############################

############################
After:
a[1][1] = mouse
a[1][2] = 777
a[2][1] = bird
a[2][2] = 888
a[3][1] = dog
a[3][2] = 999
############################
它的工作原理是首先将其转换为:

    a[1][1] = "dog"
    a[1][2] = 999
    a[2][1] = "mouse"
    a[2][2] = 777
    a[3][1] = "bird"
    a[3][2] = 888
为此:

    keys[1]   = 999
    vals[999] = dog SUBSEP 999

    keys[2]   = 777
    vals[777] = mouse SUBSEP 777

    keys[3]   = 888
    vals[888] = bird SUBSEP 888
然后asort()调用键[]以获取:

    keys[1] = 777
    keys[2] = 888
    keys[3] = 999
然后使用keys数组的元素作为vals数组的索引,循环遍历keys数组,以重新填充原始数组

如果有人想知道为什么我不只是使用我们想要排序的值作为索引,然后执行asorti(),因为那样会产生稍微简短的代码,下面是原因:

$ cat tst.awk
BEGIN {
   a[1] = 888
   a[2] = 9
   a[3] = 777

   b[888]
   b[9]
   b[777]

   print "\n\"a[]\" sorted by content:"
   asort(a,A)
   for (i=1; i in A; i++)
      print "\t" A[i]

   print "\n\"b[]\" sorted by index:"
   asorti(b,B)
   for (i=1; i in B; i++)
      print "\t" B[i]

}
$ awk -f tst.awk

"a[]" sorted by content:
        9
        777
        888

"b[]" sorted by index:
        777
        888
        9

请注意,asorti()将“9”视为高于“888”的值。这是因为asorti()根据数组索引进行排序,所有数组索引都是字符串(即使它们看起来像数字),按字母顺序排列,字符串“9”的第一个字符高于字符串“888”的第一个字符。另一方面,asort()对数组的内容进行排序,数组内容可以是字符串或数字,因此通常的awk比较规则适用-任何看起来像数字的东西都被视为数字,数字9小于数字888,在这种情况下,IMHO是期望的结果。

AFAIK,没有任何语言提供内置方法来按照用户的意愿对多维数组进行排序。(如果某些语言支持)(g)awk,请告诉我。所以你应该把手弄脏,写下你自己的逻辑。正如您所说,gawk提供
asort()
最后一个参数可以是用户定义的比较函数。你可以自由地写自己的逻辑。除此之外,还可以将二维数组转换为一维数组,并使用buildin asort()。到目前为止,您尝试了什么?最初的问题似乎是关于多维数组的排序,并且有一个公认的答案()已经超过3年了,但OP最近没有接受这个答案,发布了他们自己的答案,这只是关于填充一维数组,然后更新了他们的问题,说这是他们真正想要的,所以现在这只是关于填充关联数组的所有其他问题的重复,应该关闭,因为它不再是独立的,当然也不涉及多维数组。
    keys[1] = 777
    keys[2] = 888
    keys[3] = 999
$ cat tst.awk
BEGIN {
   a[1] = 888
   a[2] = 9
   a[3] = 777

   b[888]
   b[9]
   b[777]

   print "\n\"a[]\" sorted by content:"
   asort(a,A)
   for (i=1; i in A; i++)
      print "\t" A[i]

   print "\n\"b[]\" sorted by index:"
   asorti(b,B)
   for (i=1; i in B; i++)
      print "\t" B[i]

}
$ awk -f tst.awk

"a[]" sorted by content:
        9
        777
        888

"b[]" sorted by index:
        777
        888
        9