4

GNU awk は多次元配列をサポートしています:

q[1][1] = "dog"
q[1][2] = 999
q[2][1] = "mouse"
q[2][2] = 777
q[3][1] = "bird"
q[3][2] = 888

q私が残っているような「2番目の列」をソートしたいと思います:

q[1][1] = "mouse"
q[1][2] = 777
q[2][1] = "bird"
q[2][2] = 888
q[3][1] = "dog"
q[3][2] = 999

「最初の列」の値が 2 番目の列に合わせて移動されていることがわかります。GNU Awk はasort 関数を提供しているようですが、多次元配列をサポートしていないようです。それが役立つ場合、これは 実用的なRubyの例です:

q = [["dog", 999], ["mouse", 777], ["bird", 888]]
q.sort_by{|z|z[1]}
=> [["mouse", 777], ["bird", 888], ["dog", 999]]

私は通常の配列を使用することになり、重複を改行で区切りました:

q[777] = "mouse"
q[999] = "dog" RS "fish"
q[888] = "bird"
for (z in q) {
  print q[z]
}
4

2 に答える 2

4

FWIW、これが回避策の「sort_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

次に、元の配列を再設定するために、キー配列の要素を vals 配列のインデックスとして使用して、キー配列をループします。

並べ替えたい値をインデックスとして使用してから 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 はこの場合、私見が望ましい結果です。

于 2013-07-17T17:30:50.273 に答える
1

真の多次元配列をサポート

いいえ、そうではありません。配列の配列をサポートし、2 つのインデックスをくっつけた文字列によってインデックス付けされたハッシュをサポートします。あなたの構文は前者です(配列の配列)。

そうは言っても、ビルトインでそれを行うことはできないと思います。なぜなら、比較コールバックを使用するか、代わりに並べ替え順列を返す機能が必要になるためです。どちらもgawk提供していません。

ただし、 qsort を自分で実装する方法を説明しているこのページを参照できます。ここで、比較を からA[i] < A[left]に変更できますA[i][2] < A[left][2]

于 2013-07-17T06:48:10.820 に答える