Bash关联数组按值排序

Gra*_*raf 20 sorting bash associative-array

我得到以下输出:

Pushkin - 100500 
Gogol - 23 
Dostoyevsky - 9999
Run Code Online (Sandbox Code Playgroud)

以下脚本的结果如下:

for k in "${!authors[@]}"
do
    echo $k ' - ' ${authors["$k"]}
done   
Run Code Online (Sandbox Code Playgroud)

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

Pushkin - 100500 
Dostoyevsky - 9999
Gogol - 23
Run Code Online (Sandbox Code Playgroud)

这意味着关联数组中的键应按值排序.有一个简单的方法吗?

And*_*man 24

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

for k in "${!authors[@]}"
do
    echo $k ' - ' ${authors["$k"]}
done |
sort -rn -k3
Run Code Online (Sandbox Code Playgroud)

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

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

  • Bash 4.0添加了关联数组,其中键可以是字符串. (6认同)
  • 好吧,我会......你是对的.它只需要`declare -A authors`. (2认同)

Wer*_*ann 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 
Run Code Online (Sandbox Code Playgroud)

  • 嘘,嘘声:`echo -e`。考虑 `printf '%s\n' "${authors_indexes[@]}"` 以不依赖于违反 POSIX sh 的方式将数组扩展为多行(不仅仅是扩展,而是实际的违规:任何参数除了`-n` 需要打印其文本,除非它包含反斜杠或存在`-n`,在这种情况下,行为完全由实现定义)。或者 `printf '%s\0' "${array[@]}"` 将数组扩展为 NUL 分隔字符串,因此即使您的键中有文字换行符(*是*合法的) )。 (3认同)

Waf*_*fle 5

扩展@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
Run Code Online (Sandbox Code Playgroud)

会输出

普希金 - 10050
陀思妥耶夫斯基 - 9999
托尔斯泰 - 23
果戈理 - 23
可以在列说明符之后提供用于对特定列进行排序的选项。IEsort -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
Run Code Online (Sandbox Code Playgroud)

会输出

普希金 - 10050
陀思妥耶夫斯基 - 9999
果戈理 - 23
托尔斯泰 - 23


小智 5

按 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]
Run Code Online (Sandbox Code Playgroud)


And*_*ler 5

使用未排序的键做一些事情:

for key in ${!Map[@]}; do
   echo $key
done
Run Code Online (Sandbox Code Playgroud)

用排序的键做一些事情:

for key in $(for x in ${!Map[@]}; do echo $x; done | sort); do
   echo $key
done
Run Code Online (Sandbox Code Playgroud)

将排序后的键存储为数组:

Keys=($(for x in ${!Map[@]}; do echo $x; done | sort))
Run Code Online (Sandbox Code Playgroud)