質問
これが私の配列です(ゴークスクリプト):
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のコードから、私は機能するクイック実装を書きましたが、それはかなりugいです(比較中にソートと分割前にキーと値を連結します)。これがどのように見えるかです:
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")
}
もちろん、あなたがもっときれいなものを持っているなら私は興味があります...
御時間ありがとうございます
解決
編集:
値でソートします
おー!並べ替えます 値, 、それは少しクラッジですが、新しい配列のインデックスとしての値と元の配列のインデックスの連結を使用して、一時的な配列を作成できます。そうすれば、できます 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]}}
}
}
インデックスまたは値で移動する設定、上昇または下降、その他のオプションがあります。カスタム関数を指定することもできます。
前の答え:
インデックスでソートします
awkがある場合 gawk
3.1.2以上、サポート 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]]
}
他のヒント
パイプでunixソートコマンドを使用し、awkコードをシンプルに保ち、unix哲学に従ってください
コンマによって分離された値を持つ入力ファイルを作成します
ピーター、32
ジャック、11
ジョン、463
ボブ、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データ
ボブ、5
ジャック、11
ピーター、32
ジョン、463
PROCINFO["sorted_in"] = "@val_num_desc";
配列を反復する前に、上記のステートメントを使用してください。ただし、awkバージョン4.0.1で動作します。 awkバージョン3.1.7では機能しません。
どの中級バージョンが導入されたかはわかりません。
そして簡単な答え...
function sort_by_myArray(i1, v1, i2, v2) {
return myArray[i2] < myArray[i1];
}
BEGIN {
myArray["peter"] = 32;
myArray["bob"] = 5;
myArray["john"] = 463;
myArray["jack"] = 11;
len = length(myArray);
asorti(myArray, k, "sort_by_myArray");
# Print result.
for(n = 1; n <= len; ++n) {
print k[n], myArray[k[n]]
}
}
の著者 awkプログラミング言語 を提供する クイックソート機能, 、オンラインで入手できます。
あなたはこのようなことをするだろうと思います。
END {
for (key in myArray) {
sortkeys[j++] = key;
}
qsort(sortkeys, 0, length(myArray)); # Not sure I got the args right.
for (i = 1; i <= length(myArray); i++) {
print sortkeys[i], myArray[sortkeys[i]];
}
}