Основната причина, поради която вторият ви опит не работи, е, че се опитвате да разрешите различен проблем, като използвате същото решение.
В първия набор от данни имате два числови индексирани масива, където ключовете нямат друго значение освен вероятно реда, в който се появяват, и техните стойности са това, което наистина има значение. Тълкувах, че това означава, че искате линейно да свържете тези стойности към нов масив с нов индекс, който отхвърля предишните ключове, но поддържа първоначалния ред на елементите, както и реда, в който сте ги предали.
Вторият набор от данни има два асоциативни индексирани масива, където ключовете са стойностите, а стойностите са просто контейнери. Забелязах, че сте използвали цифрови ключове, които, ако изберете да продължите да използвате числови индексирани масиви, ще ви позволят да запазите както реда на стойностите, така и реда на ключовете, при предположението, че искате ключовете във възходящ ред...
Така че за решаването на тези проблеми имам 3 удобни функции, които съм написал, които използват declare и eval за ускоряване на присъединяването/сливането на големи масиви, вместо да използват цикли за присвояване на всеки. Те също така приемат променлив брой масиви като аргумент, така че можете да се присъедините/слеете/изхвърлите колкото искате от тях.
ЗАБЕЛЕЖКА: Промених стойността/ключа "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;
declare -a joined='([0]="5" [1]="10" [2]="15" [3]="20" [4]="25" [5]="30 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;
declare -a joined='([0]="5" [1]="10" [2]="15" [3]="20" [4]="25" [5]="30 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;
declare -A merged='([0]="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;
declare -a joined='([0]="true" [1]="true" [2]="true" [3]="true" [4]="true" [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;
declare -a joined='([0]="true" [1]="true" [2]="true" [3]="true" [4]="true" [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;
declare -A merged='([25]="true" [20]="true" ["30 30"]="true" [10]="true" [15]="true" [5]=" вярно" )'
# 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: синтактична грешка в израз (токенът за грешка е "30")
declare -p joined
declare -a joined='([0]="5" [1]="10" [2]="15" [3]="20" [4]="25" [5]="30 30" [20]="вярно" [25]="вярно")'
# 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
declare -A merged='([25]="true" [20]="true" ["30 30"]="true" [10]="true" [15]="true" [0]=" 5" [1]="10" [2]="15" [3]="20" [4]="25" [5]="true30 30" )'
Последна забележка: по-горе можете да видите, че ключ [5] има стойностите на ключа [5] на двата изходни масива, свързани, защото използвах оператора +=. Ако го използвате само за обединяване на списъци с флагове, това е безопасно, но за обединяване на списъци със значими стойности с възможни сблъсъци на ключове е по-добре да се придържате към функцията merge_array().
person
Wil
schedule
20.03.2018
[key]=value
елемента за всеки ключ. Не знам за такова разширение. Най-близкото, за което се сещам, е това, коетоdeclare -p
ви дава (което трябва да масажирате, за да използвате). - person Etan Reisner   schedule 22.04.2015