17

ここに私の配列(gawkスクリプト)があります:

myArray["peter"] = 32
myArray["bob"] = 5
myArray["john"] = 463
myArray["jack"] = 11

ソート後、次の結果が必要です。

bob    5
jack   11
peter  32
john   463

「asort」を使用すると、インデックスが失われます。インデックスを失うことなく配列値でソートする方法は? (値に基づいて順序付けられたインデックスが必要です)

(シェルスクリプトやperlなどではなく、awk/gawkのみでこの結果を取得する必要があります)

私の投稿が十分に明確でない場合は、同じ問題を説明する別の投稿があります: http://www.experts-exchange.com/Programming/Languages/Scripting/Shell/Q_26626841.html )

前もって感謝します

アップデート :

両方に感謝しますが、インデックスではなく値でソートする必要があります(値に従って順序付けされたインデックスが必要です)。

言い換えれば、私はこの結果が必要です:

bob    5
jack   11
peter  32
john   463

いいえ :

bob 5
jack 11
john 463
peter 32

(同意します、私の例は紛らわしいです、選択された値はかなり悪いです)

Catcall のコードから、動作する簡単な実装を書きましたが、かなり見栄えが悪いです (並べ替えの前にキーと値を連結し、比較中に分割します)。外観は次のとおりです。

function qsort(A, left, right,   i, last) {
  if (left >= right)
    return
  swap(A, left, left+int((right-left+1)*rand()))
  last = left
  for (i = left+1; i <= right; i++)
    if (getPart(A[i], "value") < getPart(A[left], "value"))
      swap(A, ++last, i)
  swap(A, left, last)
  qsort(A, left, last-1)
  qsort(A, last+1, right)
}

function swap(A, i, j,   t) {
  t = A[i]; A[i] = A[j]; A[j] = t
}

function getPart(str, part) {
  if (part == "key")
    return substr(str, 1, index(str, "#")-1)
  if (part == "value")
    return substr(str, index(str, "#")+1, length(str))+0
  return
}

BEGIN {  }
      {  }
END {

  myArray["peter"] = 32
  myArray["bob"] = 5
  myArray["john"] = 463
  myArray["jack"] = 11

  for (key in myArray)
    sortvalues[j++] = key "#" myArray[key]

  qsort(sortvalues, 0, length(myArray));

  for (i = 1; i <= length(myArray); i++)
    print getPart(sortvalues[i], "key"), getPart(sortvalues[i], "value")
}

もちろん、もっときれいなものがあれば興味があります...

御時間ありがとうございます

4

5 に答える 5

29

編集:

値でソート

おー!を並べ替えるには、少し手間がかかりますが、元の配列の値とインデックスを新しい配列のインデックスとして連結して、一時的な配列を作成できます。次にasorti()、一時配列を分割して、連結された値をインデックスと値に戻すことができます。その複雑な説明を理解できない場合でも、コードははるかに理解しやすいものです。また、非常に短いです。

# right justify the integers into space-padded strings and cat the index
# to create the new index
for (i in myArray) tmpidx[sprintf("%12s", myArray[i]),i] = i
num = asorti(tmpidx)
j = 0
for (i=1; i<=num; i++) {
    split(tmpidx[i], tmp, SUBSEP)
    indices[++j] = tmp[2]  # tmp[2] is the name
}
for (i=1; i<=num; i++) print indices[i], myArray[indices[i]]

編集2:

GAWK 4 を使用している場合は、明示的な並べ替えを実行せずに、値の順序で配列をトラバースできます。

#!/usr/bin/awk -f
BEGIN {
    myArray["peter"] = 32
    myArray["bob"] = 5
    myArray["john"] = 463
    myArray["jack"] = 11

    PROCINFO["sorted_in"] = "@val_num_asc"

    for (i in myArray) {
        {print i, myArray[i]}}
    }

 }

インデックスまたは値によるトラバース、昇順または降順、およびその他のオプションの設定があります。カスタム関数を指定することもできます。

以前の回答:

インデックスで並べ替え

gawk3.1.2 以降をサポートする AWK を使用している場合asorti():

#!/usr/bin/awk -f
BEGIN {
    myArray["peter"] = 32
    myArray["bob"] = 5
    myArray["john"] = 463
    myArray["jack"] = 11

    num = asorti(myArray, indices)
    for (i=1; i<=num; i++) print indices[i], myArray[indices[i]]
}

持っていない場合asorti()

#!/usr/bin/awk -f
BEGIN {
    myArray["peter"] = 32
    myArray["bob"] = 5
    myArray["john"] = 463
    myArray["jack"] = 11

    for (i in myArray) indices[++j] = i
    num = asort(indices)
    for (i=1; i<=num; i++) print i, indices[i], myArray[indices[i]]
}
于 2011-03-17T20:46:55.727 に答える
5

パイプで Unix ソート コマンドを使用し、Awk コードをシンプルに保ち、Unix の哲学に従う
カンマで区切られた値を持つ入力ファイルを作成する
peter,32
jack,11
john,463
bob,5

コードを含む sort.awk ファイルを作成します。

BEGIN { FS=","; }
{
    myArray[$1]=$2;
}
END {
    for (name in myArray)
        printf ("%s,%d\n", name, myArray[name]) | "sort -t, -k2 -n"
}

プログラムを実行すると、出力
$ awk -f sort.awk data
bob,5
jack,11
peter,32
john,463 が得られるはずです

于 2013-01-07T20:34:16.707 に答える