Sortieren Sie assoziatives Array mit awk
Frage
Hier ist mein Array (Gawk -Skript):
myArray["peter"] = 32
myArray["bob"] = 5
myArray["john"] = 463
myArray["jack"] = 11
Nach der Sortierung brauche ich das folgende Ergebnis:
bob 5
jack 11
peter 32
john 463
Wenn ich "Asort" benutze, gehen Indizes verloren. Wie sortiert man nach Array -Wert, ohne Indizes zu verlieren? (Ich brauche geordnete Indizes basierend auf ihren Werten)
(Ich muss dieses Ergebnis nur mit awk/gawk, nicht mit Shell -Skript, Perl usw. erhalten)
Wenn mein Beitrag nicht klar genug ist, ist hier ein anderer Beitrag, der dasselbe Problem erklärt: http://www.experts-exchange.com/programming/glangages/scripting/shell/q_26626841.html )
Danke im Voraus
Aktualisieren :
Vielen Dank an euch beide, aber ich muss nach Werten sortieren, nicht nach Indizes (ich möchte geordnete Indizes gemäß ihren Werten).
Mit anderen Worten brauche ich dieses Ergebnis:
bob 5
jack 11
peter 32
john 463
nicht :
bob 5
jack 11
john 463
peter 32
(Ich stimme zu, mein Beispiel ist verwirrend, die gewählten Werte sind ziemlich schlecht)
Aus dem Code von Catcall habe ich eine schnelle Implementierung geschrieben, die funktioniert, aber es ist ziemlich hässlich (ich verkette Tasten und Werte, bevor ich während des Vergleichs sortieren und aufgeteilt habe). So sieht es aus:
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")
}
Natürlich bin ich interessiert, wenn Sie etwas saubereres haben ...
Vielen Dank für Ihre Zeit
Lösung
Bearbeiten:
Sortieren nach Werten
Oh! Um die zu sortieren Werte, Es ist ein kleiner Kludge, aber Sie können ein temporäres Array mit einer Verkettung der Werte und der Indizes des ursprünglichen Arrays als Indizes im Neuarray erstellen. Dann kannst du asorti()
Das temporäre Array und teilen die verketteten Werte wieder in Indizes und Werte auf. Wenn Sie dieser verworrenen Beschreibung nicht folgen können, ist der Code viel einfacher zu verstehen. Es ist auch sehr kurz.
# 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]]
Bearbeiten 2:
Wenn Sie Gawk 4 haben, können Sie das Array nach Wertenreihenfolge durchqueren, ohne eine explizite Sorte durchzuführen:
#!/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]}}
}
}
Es gibt Einstellungen für das Durchqueren nach Index oder Wert, aufsteigend oder absteigend und andere Optionen. Sie können auch eine benutzerdefinierte Funktion angeben.
Vorherige Antwort:
Sortieren nach Indizes
Wenn Sie einen awk haben, z. gawk
3.1.2 oder mehr, was unterstützt 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]]
}
Wenn Sie nicht haben 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]]
}
Andere Tipps
Verwenden Sie den Befehl UNIX Sort
Erstellen Sie eine Eingabedatei mit von Comma getrennten Werte
Peter, 32
Jack, 11
John, 463
Bob, 5
Erstellen Sie eine sort.awk -Datei mit dem Code
BEGIN { FS=","; }
{
myArray[$1]=$2;
}
END {
for (name in myArray)
printf ("%s,%d\n", name, myArray[name]) | "sort -t, -k2 -n"
}
Führen Sie das Programm aus, sollten Sie die Ausgabe geben
$ awk -f sort.awk Daten
Bob, 5
Jack, 11
Peter, 32
John, 463
PROCINFO["sorted_in"] = "@val_num_desc";
Verwenden Sie vor dem Iterieren eines Arrays die obige Anweisung. Aber es funktioniert in awk Version 4.0.1. Es funktioniert nicht in awk Version 3.1.7.
Ich bin mir nicht sicher, in welcher Zwischenversion sie vorgestellt wurde.
Und die einfache Antwort ...
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]]
}
}
Die Autoren von Die awk -Programmiersprache zur Verfügung stellen Quicksort -Funktion, was online verfügbar ist.
Ich denke, du würdest so etwas tun.
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]];
}
}