Сортировка ассоциативных массивов Bash по значению - PullRequest
18 голосов
/ 21 ноября 2011

Я получаю следующий вывод:

Pushkin - 100500 
Gogol - 23 
Dostoyevsky - 9999

Что является результатом следующего сценария:

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

Все, что я хочу, это получить вывод, подобный этому:

Pushkin - 100500 
Dostoyevsky - 9999
Gogol - 23

, что означает, что ключи в ассоциативном массиве должны быть отсортированы по значению.Есть ли простой способ сделать это?

Ответы [ 4 ]

22 голосов
/ 21 ноября 2011

Вы можете легко отсортировать вывод в порядке убывания 3-го поля:

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

См. Sort (1) для получения дополнительной информации о команде sort.Это просто сортирует выходные строки;Я не знаю ни одного способа сортировки массива непосредственно в bash.

Я также не вижу, как вышеприведенное может дать вам имена ("Пушкин" и др.) В качестве ключей массива.В bash ключи массива всегда целые.

7 голосов
/ 02 октября 2012

В качестве альтернативы вы можете отсортировать индексы и использовать отсортированный список индексов для циклического перемещения по массиву:

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 
3 голосов
/ 18 мая 2017

Расширение ответа от @AndrewSchulman, использование -rn в качестве опции глобальной сортировки переворачивает все столбцы.В этом примере авторы с одинаковым значением ассоциативного массива будут выводиться в обратном порядке по имени.

Например,

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

будет выводить

Pushkin  -  10050
Dostoyevsky  -  9999
Tolstoy  -  23
Gogol  -  23
Могут быть предусмотрены параметры для сортировки определенных столбцов.после спецификатора столбца.т. е. sort -k3rn

Обратите внимание, что ключи могут быть указаны как промежутки.Здесь -k3 бывает хорошо, потому что это последний диапазон, но чтобы явно использовать только столбец 3 (в случае добавления дополнительных столбцов), его следует указать как -k3,3, аналогично сортировке по столбцу три в порядке убывания,и затем столбец один в порядке возрастания (что, вероятно, является тем, что требуется в этом примере):

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

выведет

Pushkin  -  10050
Dostoyevsky  -  9999
Gogol  -  23
Tolstoy  -  23
2 голосов
/ 06 февраля 2019

Лучший способ отсортировать ассоциативный массив bash по VALUE - НЕ сортировать его.

Вместо этого получите список VALUE ::: KEYS, отсортируйте этот список в новый KEY LIST и выполните итерациисписок.

declare -A ADDR
ADDR[192.168.1.3]="host3"
ADDR[192.168.1.1]="host1"
ADDR[192.168.1.2]="host2"

KEYS=$(
for KEY in ${!ADDR[@]}; do
  echo "${ADDR[$KEY]}:::$KEY"
done | sort | awk -F::: '{print $2}'
)

for KEY in $KEYS; do
  VAL=${ADDR[$KEY]}
  echo "KEY=[$KEY] VAL=[$VAL]"
done

output:
KEY=[192.168.1.1] VAL=[host1]
KEY=[192.168.1.2] VAL=[host2]
KEY=[192.168.1.3] VAL=[host3]
...