首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何在bash中组合关联数组?

如何在bash中组合关联数组?
EN

Stack Overflow用户
提问于 2015-04-22 17:29:33
回答 5查看 4.6K关注 0票数 12

有没有人知道在bash中组合两个关联数组的优雅方法,就像普通数组一样?我想说的是:

在bash中,可以组合两个普通数组,如下所示:

代码语言:javascript
运行
复制
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

我想对两个关联数组执行相同的操作,但是下面的代码不起作用:

代码语言:javascript
运行
复制
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:在分配关联数组时必须使用下标

以下是我想出的一个解决办法:

代码语言:javascript
运行
复制
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

但我希望我实际上缺少了一些语法,这将允许一行赋值,如非工作示例所示。

谢谢!

EN

回答 5

Stack Overflow用户

回答已采纳

发布于 2015-04-23 09:07:16

我也没有一个一行,但这里有一个不同的“解决办法”,有人可能喜欢使用字符串转换。它是4行,所以我只是3个分号从你想要的答案!

代码语言:javascript
运行
复制
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
票数 2
EN

Stack Overflow用户

发布于 2015-06-24 17:31:37

代码语言:javascript
运行
复制
#!/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
票数 0
EN

Stack Overflow用户

发布于 2018-03-20 05:16:22

第二次尝试失败的主要原因是,您试图使用相同的解决方案来解决不同的问题。

在第一个数据集中,您有两个数字索引数组,其中键除了它们可能出现的顺序之外没有任何意义,它们的值才是真正重要的。我将其解释为希望将这些值线性连接到一个具有新索引的新数组中,该索引丢弃了前面的键,但保持了元素的原始顺序以及传递它们的顺序。

第二个数据集有两个关联索引数组,其中键是值,值实际上只是占位符。我注意到您使用了数字键,如果您选择继续使用数字索引数组,将允许您同时保留值的顺序和键的顺序,前提是您希望这些键按升序排列.

因此,为了解决这些问题,我编写了3个方便的函数,它们使用declare和eval来加速连接/合并大型数组,而不是使用循环来分配每个数组。它们还以可变数量的数组作为参数,以便您可以随心所欲地加入/合并/转储其中的任意数量。

注意:我将"30“的值/键" 30”改为“30 30”,以演示在某些情况下字符串的行为将如何与数字不同。

代码语言:javascript
运行
复制
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 ")‘

代码语言:javascript
运行
复制
# 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 ")‘

代码语言:javascript
运行
复制
# 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“)‘

代码语言:javascript
运行
复制
# 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")’

代码语言:javascript
运行
复制
# 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")’

代码语言:javascript
运行
复制
# 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 )’

代码语言:javascript
运行
复制
# 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 ")

代码语言:javascript
运行
复制
declare -p joined

声明-a joined='(="5“1="10”“2="15”3="20“4="25”5=" 30“20=”真“25=”true)‘

代码语言:javascript
运行
复制
# 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()函数。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/29804909

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档