Merging two Bash arrays into key:value pairs via a Cartesian product
Asked Answered
Z

5

53

I have two arrays A and B. How do I combine them into a new array C, which is their Cartesian product? For example, given:

A=( 0 1 )
B=( 1 2 )

Desired output:

C=( 0:1 0:2 1:1 1:2 )
Zobkiw answered 31/12, 2009 at 16:29 Comment(0)
V
20

Since Bash supports sparse arrays, it's better to iterate over the array than to use an index based on the size.

a=(0 1); b=(2 3)
i=0
for z in ${a[@]}
do
    for y in ${b[@]}
    do
        c[i++]="$z:$y"
    done
done
declare -p c   # dump the array

Outputs:

declare -a c='([0]="0:2" [1]="0:3" [2]="1:2" [3]="1:3")'
Viyella answered 31/12, 2009 at 16:47 Comment(0)
P
159

If you don't care about having duplicates, or maintaining indexes, then you can concatenate the two arrays in one line with:

NEW=("${OLD1[@]}" "${OLD2[@]}")

Full example:

Unix=('Debian' 'Red hat' 'Ubuntu' 'Suse' 'Fedora' 'UTS' 'OpenLinux');
Shell=('bash' 'csh' 'jsh' 'rsh' 'ksh' 'rc' 'tcsh');
UnixShell=("${Unix[@]}" "${Shell[@]}")
echo ${UnixShell[@]}
echo ${#UnixShell[@]}

Credit: http://www.thegeekstuff.com/2010/06/bash-array-tutorial/

Pinebrook answered 26/7, 2016 at 0:6 Comment(8)
This concatenates the two arrays which is not what the OP wants.Viyella
@DennisWilliamson, Yep, but Google will send thousands of people here looking for this answer. I'm glad it's here.Ratfink
While it's a useful technique, it should also be noted that the indices of the source arrays are lost. When the destination array is created, new indices are generated.Viyella
Anyone who wants to use this method should test it thoroughly before putting it in their code. When -n is in one of the arrays, it is omitted in the merged array. To see this, run the following code: a=(-m -n -o); b=(-p -q -r); c=("${a[@]}" "${b[@]}"); for i in "${c[@]}"; do echo $i; done. Also, putting it in quotes doesn't help.Sheathbill
@Dave F, the missing -n is not an issue of the array concatination. That works as expected. It is missing, because echo interprets it as an option to not output a newline.Cognition
why does this work?Pygmy
This is a fine answer to my question: https://mcmap.net/q/340331/-how-do-i-combine-two-arrays-into-a-third-array-duplicate/9636Swampland
I disagree with the notion that we should dilute the quality of SE answers because search engines aren't (yet) discerning enough to allow mindless click through without reading the title. That creates a garbage in, garbage out future.Laborsaving
V
20

Since Bash supports sparse arrays, it's better to iterate over the array than to use an index based on the size.

a=(0 1); b=(2 3)
i=0
for z in ${a[@]}
do
    for y in ${b[@]}
    do
        c[i++]="$z:$y"
    done
done
declare -p c   # dump the array

Outputs:

declare -a c='([0]="0:2" [1]="0:3" [2]="1:2" [3]="1:3")'
Viyella answered 31/12, 2009 at 16:47 Comment(0)
L
5

here's one way

a=(0 1)
b=(1 2)
for((i=0;i<${#a[@]};i++));
do
    for ((j=0;j<${#b[@]};j++))
    do
        c+=(${a[i]}:${b[j]});
    done
done

for i in ${c[@]}
do
    echo $i
done
Liebermann answered 31/12, 2009 at 16:47 Comment(1)
The second for loop should use double quotes around the array reference. This preserves significant spaces in the array values. Try it with a=("foo bar" "baz quux"). The c+= assignment similarly needs to quote the new value.Ellita
C
0

Here is how I merged two arrays in Bash:

Example arrays:

AR=(1 2 3) BR=(4 5 6)

One Liner:

CR=($(echo ${AR[*]}) $(echo ${BR[*]}))

Carleencarlen answered 14/8, 2018 at 18:44 Comment(2)
There's no need to use $() and this doesn't preserve spaces in the values (if they exist). a=("some words" some single words) b=(one two three "words with spaces") n=("${a[@]}" "${b[@]}") You can also just append to one of them with += a+=("${b[@]}") `Wish
This only works if every element is space delimited. If you used readarray to feed elements in based on lines this will not work.Surfing
G
-2

One line statement to merge two arrays in bash:

combine=( `echo ${array1[@]}` `echo ${array2[@]}` )
Generality answered 31/1, 2018 at 12:8 Comment(2)
That will re-split the elements. You probably meant combine=("${array1[@]}" "${array2[@]}"). Which is then what Ian Dunn said.Hortensehortensia
The quoting error is exacerbated by the useless use of echoEllita

© 2022 - 2024 — McMap. All rights reserved.