2011-11-21 17 views
16

me sale el siguiente resultado:Bash matriz asociativa de clasificación

Pushkin - 100500 
Gogol - 23 
Dostoyevsky - 9999 

que es el resultado de la siguiente secuencia de comandos:

for k in "${!authors[@]}" 
do 
    echo $k ' - ' ${authors["$k"]} 
done 

Todo lo que quiero es conseguir la salida de la siguiente manera:

Pushkin - 100500 
Dostoyevsky - 9999 
Gogol - 23 

lo que significa que las claves de la matriz asociativa deben ordenarse por valor. ¿Hay un método fácil para hacerlo?

Respuesta

17

Puede ordenar fácilmente su salida, en orden numérico descendente de la tercera campo:

for k in "${!authors[@]}" 
do 
    echo $k ' - ' ${authors["$k"]} 
done | 
sort -rn -k3 

vea sort (1) para más información sobre el comando sort. Esto solo ordena líneas de salida; No sé de ninguna manera para ordenar una matriz directamente en bash.

Tampoco puedo ver cómo los anteriores pueden darle nombres ("Pushkin" et al.) Como teclas de matriz. En bash, las teclas de matriz siempre son números enteros.

+6

Bash 4.0 añade matrices asociativas donde las claves pueden ser cadenas. –

+2

Bueno, yo seré ... tienes razón. Solo necesita 'declarar -A autores'. –

+1

Su solución funciona. Por lo que yo entiendo, solo ordena cadenas de salida, no los contenidos de la matriz asociativa, pero de todos modos, la salida producida es lo que necesito. – Graf

7

Alternativamente puede ordenar los índices y el uso de la lista ordenada de los índices para recorrer la matriz:

authors_indexes=(${!authors[@]}) 
IFS=$'\n' authors_sorted=($(echo -e "${authors_indexes[@]/%/\n}" | sed -r -e 's/^ *//' -e '/^$/d' | sort)) 

for k in "${authors_sorted[@]}"; do 
    echo $k ' - ' ${authors["$k"]} 
done 
+0

Boo, siseo: 'echo -e'. Considere 'printf '% s \ n'" $ {authors_indexes [@]} "' para expandir una matriz en varias líneas de una manera que no dependa de las violaciones de POSIX sh (no solo extensiones, sino violaciones reales: cualquier argumento que no sea '-n' es necesario para imprimir su texto, a menos que contenga barras invertidas o' -n', en cuyo caso el comportamiento está completamente definido por la implementación). O 'printf '% s \ 0'" $ {array [@]} "' para expandir la matriz como cadenas de delimitación NUL, de forma que funcione incluso si tiene nuevas líneas literales en las teclas (que * son * legales) –

+0

... vea http://pubs.opengroup.org/onlinepubs/009695399/utilities/echo.html, especialmente la sección USO DE LA APLICACIÓN. –

2

La extensión de la respuesta de @AndrewSchulman, utilizando -rn como una opción global especie invierte todas las columnas. En este ejemplo, los autores con el mismo valor de matriz asociativa saldrán por orden inverso del nombre.

Por ejemplo

declare -A authors 
authors=([Pushkin]=10050 [Gogol]=23 [Dostoyevsky]=9999 [Tolstoy]=23) 

for k in "${!authors[@]}" 
do 
    echo $k ' - ' ${authors["$k"]} 
done | sort -rn -k3 

salida se

 
Pushkin - 10050 
Dostoyevsky - 9999 
Tolstoy - 23 
Gogol - 23 
opciones para ordenar columnas específicas se puede proporcionar después de que el especificador de columna. es decir, sort -k3rn

Tenga en cuenta que las claves se pueden especificar como tramos. Aquí -k3 está bien porque es el tramo final, pero para usar solo la columna 3 explícitamente (en caso de que se hayan agregado más columnas), debe especificarse como -k3,3, De forma similar para ordenar por columna tres en orden descendente, y luego columna una en orden ascendente (que es probablemente lo que se desea en este ejemplo):

declare -A authors 
authors=([Pushkin]=10050 [Gogol]=23 [Dostoyevsky]=9999 [Tolstoy]=23) 
for k in "${!authors[@]}" 
do 
    echo $k ' - ' ${authors["$k"]} 
done | sort -k3,3rn -k1,1 

es la salida

 
Pushkin - 10050 
Dostoyevsky - 9999 
Gogol - 23 
Tolstoy - 23