有没有人知道在bash中组合两个关联数组的优雅方法,就像普通数组一样?我想说的是:
在bash中,可以组合两个普通数组,如下所示:
declare -ar array1=( 5 10 15 )
declare -ar array2=( 20 25 30 )
declare -ar array_both=( ${array1[@]} ${array2[@]} )
for item in ${array_both[@]}; do
echo "Item: ${item}"
done我想对两个关联数组执行相同的操作,但是下面的代码不起作用:
declare -Ar array1=( [5]=true [10]=true [15]=true )
declare -Ar array2=( [20]=true [25]=true [30]=true )
declare -Ar array_both=( ${array1[@]} ${array2[@]} )
for key in ${!array_both[@]}; do
echo "array_both[${key}]=${array_both[${key}]}"
done它给出了以下错误:
./ associative _arrays.sh:第3行: array_both: true:在分配关联数组时必须使用下标
以下是我想出的一个解决办法:
declare -Ar array1=( [5]=true [10]=true [15]=true )
declare -Ar array2=( [20]=true [25]=true [30]=true )
declare -A array_both=()
for key in ${!array1[@]}; do
array_both+=( [${key}]=${array1[${key}]} )
done
for key in ${!array2[@]}; do
array_both+=( [${key}]=${array2[${key}]} )
done
declare -r array_both
for key in ${!array_both[@]}; do
echo "array_both[${key}]=${array_both[${key}]}"
done但我希望我实际上缺少了一些语法,这将允许一行赋值,如非工作示例所示。
谢谢!
发布于 2015-04-23 09:07:16
我也没有一个一行,但这里有一个不同的“解决办法”,有人可能喜欢使用字符串转换。它是4行,所以我只是3个分号从你想要的答案!
declare -Ar array1=( [5]=true [10]=true [15]=true )
declare -Ar array2=( [20]=true [25]=true [30]=true )
# convert associative arrays to string
a1="$(declare -p array1)"
a2="$(declare -p array2)"
#combine the two strings trimming where necessary
array_both_string="${a1:0:${#a1}-3} ${a2:21}"
# create new associative array from string
eval "declare -A array_both="${array_both_string#*=}
# show array definition
for key in ${!array_both[@]}; do
echo "array_both[${key}]=${array_both[${key}]}"
done发布于 2015-06-24 17:31:37
#!/bin/bash
function merge_hashes() {
local -n DEST_VAR=$1
shift
local -n SRC_VAR
local KEY
for SRC_VAR in $@; do
for KEY in "${!SRC_VAR[@]}"; do
DEST_VAR[$KEY]="${SRC_VAR[$KEY]}"
done
done
}
declare -Ar array1=( [5]=true [10]=true [15]=true )
declare -Ar array2=( [20]=true [25]=true [30]=true )
declare -A array_both=()
# And here comes the one-liner:
merge_hashes array_both array1 array2
declare -p array_both发布于 2018-03-20 05:16:22
第二次尝试失败的主要原因是,您试图使用相同的解决方案来解决不同的问题。
在第一个数据集中,您有两个数字索引数组,其中键除了它们可能出现的顺序之外没有任何意义,它们的值才是真正重要的。我将其解释为希望将这些值线性连接到一个具有新索引的新数组中,该索引丢弃了前面的键,但保持了元素的原始顺序以及传递它们的顺序。
第二个数据集有两个关联索引数组,其中键是值,值实际上只是占位符。我注意到您使用了数字键,如果您选择继续使用数字索引数组,将允许您同时保留值的顺序和键的顺序,前提是您希望这些键按升序排列.
因此,为了解决这些问题,我编写了3个方便的函数,它们使用declare和eval来加速连接/合并大型数组,而不是使用循环来分配每个数组。它们还以可变数量的数组作为参数,以便您可以随心所欲地加入/合并/转储其中的任意数量。
注意:我将"30“的值/键" 30”改为“30 30”,以演示在某些情况下字符串的行为将如何与数字不同。
join_arrays(){
# <array> [<array> ...] <destination array>
# linear concatenates the values, re-keys the result.
# works best with indexed arrays where order is important but index value is not.
local A_;
while (( $# > 1 )); do
A_+="\"\${$1[@]}\" ";
shift;
done
eval "$1=($A_)";
}
# This works by building and running an array assignment command
# join_array a1 a2 a3 becomes a3=("${a1[@]" "$a2[@]" );
merge_arrays(){
# <array> [<array> ...] <destination array>
# merges the values, preserves the keys.
# works best with assoc arrays or to obtain union-like results.
# if a key exists in more than one array the latter shall prevail.
local A_ B_;
while (( $# > 1 )); do
B_=`declare -p $1`;
B_=${B_#*=??};
A_+=${B_::-2}" ";
shift;
done
eval "$1=($A_)";
}
# this crops the output of declare -p for each array
# then joining them into a single large assignment.
# try putting "echo" in front of the eval to see the result.
dump_arrays(){
# <array> [<array> ...]
# dumps array nodes in bash array subscript assignment format
# handy for use with array assignment operator. Preseves keys.
# output is a join, but if you assign it you obtain a merge.
local B_;
while (( $# > 0 )); do
B_=`declare -p $1`;
B_=${B_#*=??};
printf "%s " "${B_::-2}";
shift;
done
}
# same as above but prints it instead of performing the assignment
# The data sets, first the pair of indexed arrays:
declare -a array1=( 5 10 15 );
declare -a array2=( 20 25 "30 30" );
# then the set of assoc arrays:
declare -a array3=( [5]=true [10]=true [15]=true );
declare -a array4=( [20]=true [25]=true ["30 30"]=true );
# show them:
declare -p array1 array2 array3 array4;
# an indexed array for joins and an assoc array for merges:
declare -a joined;
declare -A merged;
# the common way to join 2 indexed arrays' values:
echo "joining array1+array2 using array expansion/assignment:";
joined=( "${array1[@]}" "${array2[@]}" );
declare -p joined;声明-a joined='(="5“1="10”“2="15”3="20“4="25”5=" 30 ")‘
# this does exactly the same thing, mostly saves me from typos ;-)
echo "joining array1+array2 using join_array():";
join_arrays array1 array2 joined;
declare -p joined;声明-a joined='(="5“1="10”“2="15”3="20“4="25”5=" 30 ")‘
# this merges them by key, which is inapropriate for this data set
# But I've included it for completeness to contrast join/merge operations
echo "merging array1+array2 using merge_array():";
merge_arrays array1 array2 merged;
declare -p merged;声明-A merged='(="20“1="25”2="30 30“)‘
# Example of joining 2 associative arrays:
# this is the usual way to join arrays but fails because
# the data is in the keys, not the values.
echo "joining array3+array4 using array expansion/assignment:"
joined=( "${array3[@]}" "${array4[@]}" );
declare -p joined;声明-a joined=‘(=“真”1=真“2=”真“3=”真“4=”真“5="true")’
# and again, a join isn't what we want here, just for completeness.
echo "joining array3+array4 using join_array():";
join_arrays array3 array4 joined;
declare -p joined;声明-a joined=‘(=“真”1=真“2=”真“3=”真“4=”真“5="true")’
# NOW a merge is appropriate, because we want the keys!
echo "merging array3+array4 using merge_array():"
merge_arrays array3 array4 merged;
declare -p merged;声明-A merged=‘(25=“真”“20="true”30 30“=”10=“真”15=“真”5=“true )’
# Bonus points - another easy way to merge arrays (assoc or indexed) by key
# Note: this will only work if the keys are numeric...
join_arrays array1 array2 joined;
# error expected because one keys is "30 30" ...
eval joined+=(`dump_arrays merged`);bash: 30:表达式中的语法错误(错误标记为" 30 ")
declare -p joined声明-a joined='(="5“1="10”“2="15”3="20“4="25”5=" 30“20=”真“25=”true)‘
# Note: assoc arrays will not be sorted, even if keys are numeric!
join_arrays array1 array2 joined;
eval merged+=(`dump_arrays joined`);
declare -p merged声明-A merged=‘(25=“真”“20=”真" 30“=”10=“真”15=“真”="5“1="10”2="15“3="20”4="25“5="true30 30”)’
最后注意:上面可以看到Key 5具有两个源数组键5的值,因为我使用了+=操作符。如果您只是将它用于合并标志列表,这是安全的,但是对于将有意义的值列表与可能的键冲突合并起来,最好坚持使用merge_array()函数。
https://stackoverflow.com/questions/29804909
复制相似问题