Bash关联数组按值排序

时间:2011-11-21 18:59:15

标签: bash associative-array sorting

我得到以下输出:

Pushkin - 100500 
Gogol - 23 
Dostoyevsky - 9999

以下脚本的结果如下:

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

我想要的就是得到这样的输出:

Pushkin - 100500 
Dostoyevsky - 9999
Gogol - 23

表示关联数组中的键应按值排序。有一种简单的方法吗?

5 个答案:

答案 0 :(得分:22)

您可以按第3个字段的降序数字轻松对输出进行排序:

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

有关sort命令的更多信息,请参阅sort(1)。这只是排序输出线;我不知道有什么方法可以直接在bash中对数组进行排序。

我也看不出上面的内容如何将你的名字(“Pushkin”等)作为数组键。在bash中,数组键总是整数。

答案 1 :(得分:7)

或者,您可以对索引进行排序并使用排序的索引列表循环遍历数组:

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 

答案 2 :(得分:3)

从@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

答案 3 :(得分:1)

按VALUE排序bash关联数组的最好方法是不对其进行排序。

相反,获取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]

答案 4 :(得分:0)

如果您可以假设该值始终是一个数字(没有空格),但希望允许键中有空格的可能性:

for k in "${!authors[@]}"; do 
  echo "${authors["$k"]} ${k}"
done | sort -rn | while read number author; do 
  echo "${author} - ${number}"
done

示例:

$ declare -A authors
$ authors=(['Shakespeare']=1 ['Kant']=2 ['Von Neumann']=3 ['Von Auersperg']=4)
$ for k in "${!authors[@]}"; do echo "${authors["$k"]} ${k}"; done | sort -rn | while read number author; do echo "${author} - ${number}"; done
Von Auersperg - 4
Von Neumann - 3
Kant - 2
Shakespeare - 1
$ 

如果键中没有空格,则所选答案似乎有效,但如果有则失败:

$ declare -A authors
$ authors=(['Shakespeare']=1 ['Kant']=2 ['Von Neumann']=3 ['Von Auersperg']=4)
$ for k in "${!authors[@]}"; do echo $k ' - ' ${authors["$k"]}; done | sort -rn -k 3
Kant  -  2
Shakespeare  -  1
Von Neumann  -  3
Von Auersperg  -  4
$