Arrays 如何根据关联数组中的值对关联数组的索引数组重新排序?

Arrays 如何根据关联数组中的值对关联数组的索引数组重新排序?,arrays,bash,multidimensional-array,associative-array,Arrays,Bash,Multidimensional Array,Associative Array,在shell代码中,我有一个索引数组,包含关联数组的名称: declare -A assoc1=([name]=aaa [age]=20) declare -A assoc2=([name]=bbb [age]=40) declare -A assoc3=([name]=ccc [age]=25) indexed_array=(assoc1 assoc2 assoc3) 因此,使用上面的,${indexed_array[@]}等于assoc1 assoc2 assoc3 我想要一个sort_a

在shell代码中,我有一个索引数组,包含关联数组的名称:

declare -A assoc1=([name]=aaa [age]=20)
declare -A assoc2=([name]=bbb [age]=40)
declare -A assoc3=([name]=ccc [age]=25)
indexed_array=(assoc1 assoc2 assoc3)
因此,使用上面的,
${indexed_array[@]}
等于
assoc1 assoc2 assoc3

我想要一个
sort_array
函数,它可以对
索引_array
中的值重新排序,以便将具有最高年龄(assoc2)的关联数组列在前面或最后,如下所示:

new_indexed_array=( $(echo ${indexed_array[@]} | sort_by 'age' 'desc') )
之后,我应该在新数组中获得重新排序的内容:

declare -p new_indexed_array
# gives "assoc2 assoc3 assoc1"
我有一些样板代码来获取数组值,但无法进一步对数组进行排序

函数排序依据{
#对于给定数组中的每个哈希
get_stdin#(自定义函数,设置$stdin)
用于${STDIN[@]}中的哈希
做
#获取散列键
hash_keys=“$(eval”echo\${!$hash[@]}”)
#每把钥匙
对于$hash_keys中的hashkey
做
#重置
返回\u数组=false
#如果$hashkey与给定的键匹配
如果[“$hashkey”=“$1”];则
#如果最高/最低,请检查此值
#(与以前的相比)
#如果是/生产任务(asc/desc),则返回
fi
#如果$return\u\u array=true,那么我们找到了正确的键并
#高/低
如果[“$return_the_array”=true];则
#做事
fi
完成
完成
}

如果您有Bash 4.3或更新版本,可以使用namerefs,如下所示:

sort_by() {
    local arr field sort_params elem
    declare -n arr=$1
    field=$2

    # Build array with sort parameters
    [[ $3 == 'desc' ]] && sort_params+=('-r')
    [[ $field == 'age' ]] && sort_params+=('-n')

    # Schwartzian transform
    for elem in "${arr[@]}"; do
        declare -n ref=$elem
        printf '%s\t%s\n' "${ref["$field"]}" "$elem"
    done | sort "${sort_params[@]}" | cut -f2
}

declare -A assoc1=([name]=aaa [age]=20)
declare -A assoc2=([name]=bbb [age]=40)
declare -A assoc3=([name]=ccc [age]=25)
indexed_array=(assoc1 assoc2 assoc3)

readarray -t byage < <(sort_by indexed_array age desc)
declare -p byage

readarray -t byname < <(sort_by indexed_array name asc)
declare -p byname
而输出是每行一个元素,因此要将其读回数组,我们必须使用类似于
readarray
(参见最后的示例)的方法

首先,我们使用nameref将arrayname分配给
arr

declare -n arr=$1
arr
现在的行为就像它是实际数组一样

然后,我们用
sort
的参数构建一个数组:如果第三个参数是
desc
,我们使用
-r
,如果字段是
age
,我们使用
-n
。这可以变得更智能一些,检查字段是否包含数值,并相应地设置
-n

然后,我们迭代
arr
的元素,这些元素是关联数组的名称。在循环中,我们将名称分配给
ref

declare -n ref=$elem
ref
现在的行为类似于实际的关联数组

要排序,我们使用(修饰–排序–取消修饰),方法是打印带有所选字段名的行,然后打印数组名;例如,对于
age
,我们会

20      assoc1
40      assoc2
25      assoc3
使用适当的参数将其输送到
sort
,然后使用
cut-f2
再次删除排序字段

示例的输出如下所示:

declare -a byage=([0]="assoc2" [1]="assoc3" [2]="assoc1")
declare -a byname=([0]="assoc1" [1]="assoc2" [2]="assoc3")

请注意,
declare-n
在函数中声明本地参数,这样它们就不会污染全局名称空间。

仅供参考,我使用的是已接受答案的修改版本:

函数排序依据{
局部字段排序参数元素
字段=$1
#使用排序参数生成数组
[[$2=='desc']]&&sort_参数+=('-r')
[[$field=='age']&&sort_params+=('-n')
#施瓦茨变换,
#从$(cat)获取管道数组内容
当读的时候,要读
declare-n ref=$elem
printf'%s\t%s\n'${ref[“$field”]}”“$elem”
完成| sort“${sort_params[@]}”| cut-f2 | tr'\n''
}
此函数与已接受答案之间的区别在于,上述函数希望将索引数组的内容作为管道输入接收,而不是将数组名称作为第一个参数

因此,我的函数可以这样调用:

echo${someIndexedArray[@]}按“年龄”排序
(此func输出同一行上的所有内容,而不是换行)


这(对我来说)的好处是,它现在在我使用的CMS中工作,而且,
sort_by
函数不需要知道数组的名称-CMS不会传递该名称。

将数据存储为换行分隔的csv文件会更容易。然后排序是一个简单的
排序
。我会在读取-r元素时执行
,而不是对$(cat)
中的元素进行
。啊,我明白了。。。好的,谢谢,这很有效,而且不需要启动sub-shell。。很好,干杯。。我已经编辑了上面的代码
declare -a byage=([0]="assoc2" [1]="assoc3" [2]="assoc1")
declare -a byname=([0]="assoc1" [1]="assoc2" [2]="assoc3")