sorta di matrice associativa con AWK
Domanda
Ecco il mio array (scritto gawk):
myArray["peter"] = 32
myArray["bob"] = 5
myArray["john"] = 463
myArray["jack"] = 11
Dopo sorta, mi serve il seguente risultato:
bob 5
jack 11
peter 32
john 463
Quando uso "asort", gli indici sono persi. Come per ordinare per valore di matrice senza perdere indici? (Ho bisogno ordinato indici in base ai loro valori)
(ho bisogno di ottenere questo risultato con awk / gawk solo, non script di shell, perl, ecc)
Se il mio post non è abbastanza chiaro, qui è un altro post che spiega lo stesso problema: http://www.experts-exchange.com/Programming/Languages/Scripting/Shell/Q_26626841.html )
Grazie in anticipo
Aggiornamento:
Grazie a tutti e due, ma ho bisogno di Ordina per valori, non indici (voglio ordinato indici in base ai loro valori).
In altri termini, ho bisogno di questo risultato:
bob 5
jack 11
peter 32
john 463
non
bob 5
jack 11
john 463
peter 32
(sono d'accordo, il mio esempio è confusa, i valori scelti sono piuttosto male)
Dal codice di catcall, ho scritto una rapida attuazione che le opere, ma è piuttosto brutto (I concateno chiavi e valori prima di ordinamento e di divisione durante il confronto). Ecco come si presenta:
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")
}
Naturalmente mi interessa se hai qualcosa di più pulito ...
Grazie per il vostro tempo
Soluzione
Modifica
Ordina per valori
Oh! Per ordinare i Valori , è un po 'un ripiego, ma è possibile creare un array temporaneo utilizzando una concatenazione dei valori e gli indici della matrice originale come indici del nuovo array. Poi si può asorti()
l'array temporaneo e dividere i valori concatenati di nuovo in indici e valori. Se non è possibile seguire questa descrizione contorto, il codice è molto più facile da capire. E 'anche molto breve.
# 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]]
Modifica 2:
Se avete GAWK 4, si può attraversare la matrice per ordine di valori senza eseguire una sorta esplicito:
#!/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]}}
}
}
Ci sono le impostazioni per l'attraversamento da indice o il valore, ascendente o discendente e altre opzioni. È inoltre possibile specificare una funzione personalizzata.
Risposta precedente:
Ordina per indici
Se si dispone di un AWK, come ad esempio gawk
3.1.2 o superiore, che supporta 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]]
}
Se non si dispone di 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]]
}
Altri suggerimenti
Il comando tipo Unix con il tubo, mantiene il codice Awk semplice e seguire Unix filosofia
Creare un file di input con i valori separati da virgola
peter, 32
Jack, 11
John, 463
bob, 5
Creare un file sort.awk con il codice
BEGIN { FS=","; }
{
myArray[$1]=$2;
}
END {
for (name in myArray)
printf ("%s,%d\n", name, myArray[name]) | "sort -t, -k2 -n"
}
Eseguire il programma, dovrebbe dare l'uscita
$ Awk -f sort.awk dati
bob, 5
Jack, 11
peter, 32
John, 463
PROCINFO["sorted_in"] = "@val_num_desc";
Prima di iterare una matrice, utilizzare la dichiarazione di cui sopra. Ma, funziona in awk versione 4.0.1. Non funziona in awk versione 3.1.7.
Non sono sicuro in cui versione intermedia, ha ottenuto introdotto.
E la risposta è semplice ...
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]]
}
}
Gli autori di L'AWK Programming Language di fornire un Quicksort funzione , che è disponibile on-line.
Credo che avresti fatto qualcosa di simile.
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]];
}
}