如何保持关联数组顺序?

时间:2015-03-20 07:15:53

标签: arrays bash loops

我尝试在Bash中迭代一个关联数组。

看起来很简单,但循环不遵循数组的初始顺序。

这是一个简单的尝试脚本:

#!/bin/bash

echo -e "Workspace\n----------";
lsb_release -a

echo -e "\nBash version\n----------";
echo -e $BASH_VERSION."\n";

declare -A groups;
groups["group1"]="123";
groups["group2"]="456";
groups["group3"]="789";
groups["group4"]="abc";
groups["group5"]="def";

echo -e "Result\n----------";
for i in "${!groups[@]}"
do
    echo "$i => ${groups[$i]}";
done

输出:

Workspace
----------
No LSB modules are available.
Distributor ID: Ubuntu
Description:    Ubuntu 14.04.2 LTS
Release:    14.04
Codename:   trusty

Bash version
----------
4.3.11(1)-release.

Result
----------
group3 => 789
group2 => 456
group1 => 123
group5 => def
group4 => abc

为什么我没有group1group2等?

我不想要一个alphanum命令,我只是希望循环遵循数组的初始声明的顺序...

有办法吗?

3 个答案:

答案 0 :(得分:26)

正如已经指出的那样,没有错。关联数组存储在'哈希'订购。如果您想订购,则不要使用关联数组。或者,您使用非关联数组以及关联数组。

保留第二个(非关联)数组,以按照它们创建的顺序标识键。然后逐步执行第二个数组,使用其内容在打印数据时键入第一个(关联)数组。像这样:

declare -A groups;      declare -a orders;
groups["group1"]="123"; orders+=( "group1" )
groups["group2"]="456"; orders+=( "group2" )
groups["group3"]="789"; orders+=( "group3" )
groups["group4"]="abc"; orders+=( "group4" )
groups["group5"]="def"; orders+=( "group5" )

# Convoluted option 1
for i in "${!orders[@]}"
do
    echo "${orders[$i]}: ${groups[${orders[$i]}]}"
done
echo

# Convoluted option 1 - 'explained'
for i in "${!orders[@]}"
do
    echo "$i: ${orders[$i]}: ${groups[${orders[$i]}]}"
done
echo

# Simpler option 2 - thanks, PesaThe
for i in "${orders[@]}"
do
    echo "$i: ${groups[$i]}"
done

更简单的选项2'是PesaThecomment中建议的,应优先使用'错综复杂的选项'。

示例输出:

group1: 123
group2: 456
group3: 789
group4: abc
group5: def

0: group1: 123
1: group2: 456
2: group3: 789
3: group4: abc
4: group5: def

group1: 123
group2: 456
group3: 789
group4: abc
group5: def

你可能不希望每行有两个语句,但它强调了两个数组处理之间的并行性。

问题中的分配后的分号并非真的有必要(虽然它们没有任何积极的伤害,除了让读者不知道为什么?')。

答案 1 :(得分:4)

对关联数组中的条目进行排序的另一种方法是在将组添加为关联数组中的条目时保留组的列表。将此条目键称为“group_list”。在添加每个新组时,将其附加到group_list字段,添加空格以分隔后续添加。这是我为一个名为master_array的关联数组所做的一个:

master_array["group_list"]+="${new_group}";

要按照添加顺序对组进行排序,请按 for 循环中的group_list字段进行排序,然后可以访问关联数组中的组字段。这是我为master_array写的一个代码片段:

for group in ${master_array["group_list"]}; do
    echo "${group}";
    echo "${master_array[${group},destination_directory]}";
done

这是该代码的输出:

"linux"
"${HOME}/Backup/home4"
"data"
"${HOME}/Backup/home4/data"
"pictures"
"${HOME}/Backup/home4/pictures"
"pictures-archive"
"${HOME}/Backup/home4/pictures-archive"
"music"
"${HOME}/Backup/home4/music"

这类似于Jonathan Leffler的建议,但是使用关联数组保存数据,而不是需要保留两个单独的不相交数组。正如您所看到的,它不是按随机顺序排列,也不是按字母顺序排列,而是按顺序添加到数组中。

此外,如果您有子组,则可以为每个组创建子组列表,并按顺序排列。这就是我这样做的原因,以减少多个数组访问关联数组的需要,并且允许扩展到新的子组而不必修改代码。

编辑:修正了一些错别字

答案 2 :(得分:1)

我的方法是先创建一个排序的键数组:

keys=( $( echo ${!dict[@]} | tr ' ' $'\n' | sort ) )
for k in ${keys[@]}; do
    echo "$k=${dict[$k]}"
done