I am trying to merge two arrays into one in a zipper like fashion. I have difficulty to make that happen.
array1=(one three five seven)
array2=(two four six
< Update >This below solution is designed to work with data delimited by newlines: each value to be loaded into the array on a separate line in each file. Works perfectly as written, but if your data is organized differently, please see @Socowi 's alternative using paste
with printf
in the comments. Much thanks to @Socowi for both raising the issue & offering a workaround for data delimited in other ways! < / Update >
Here's another solution to interleave data from (2) arrays which are populated with data delimited by newlines in separate files. This solution uses paste
, echo
& xargs
:
Array Data: I feed files to arrays because I like to disaggregate data from code. Following files with each value delimited by a newline will be consumed by readarray
:
test1.txt:
one
three
five
seven
test2.txt:
two
four
six
eight
Put it all together:
#!/bin/bash
readarray arrayTest1 < /root/test1.txt
readarray arrayTest2 < /root/test2.txt
paste <( echo "${arrayTest1[*]}" ) <( echo "${arrayTest2[*]}" ) | xargs
Output:
one two three four five six seven eight
This is based on RTLinuxSW's answer, with the improvement from Paused until further notice's comment, which adds support for sparse and associative arrays.
for index in "${!array1[@]}"; do # Also, quote indices
result+=( "${array1[$index]}" "${array2[$index]}" )
done
After:
$ echo "${result[@]}"
one two three four five six seven eight
$ declare -p result
declare -a result=([0]="one" [1]="two" [2]="three" [3]="four" [4]="five" [5]="six" [6]="seven" [7]="eight")
This assumes the indices of the two arrays are identical.
You can easily read the files, create an array with their content, check who is the bigger one and make the loop.
#!/usr/bin/env bash
## Writting a until d into the file file01 and writing 1 until 3 into the file file02.
echo {a..d} | tee file01
echo {1..3} | tee file02
## Declaring two arrays (FILE01 and FILE02) and a variable as integer.
declare -a FILE01=($(<file1))
declare -a FILE02=($(<file2))
declare -i COUNT=0
## Checking who is the biggest array and declaring the ARRAY_SIZE.
[[ "${#FILE01[@]}" -ge "${#FILE02[@]}" ]] && declare -i ARRAY_SIZE="${#FILE01[@]}" || declare -i ARRAY_SIZE="${#FILE02[@]}"
## Creating the loop (COUNT must be lesser or equal ARRAY_SIZE) and print each element of each array (FILE01 and FILE02).
while [ ${COUNT} -le ${ARRAY_SIZE} ]; do
echo -n "${FILE01[$COUNT]} ${FILE02[$COUNT]} "
((COUNT++))
done
declare -a
-> It creates an array
declare -i
-> It declares the var as integer
${#FILE01[@]}
-> It's to get the array size
Assuming both arrays are the same size,
unset result
for (( i=0; i<${#array1[*]}; ++i)); do
result+=( "${array1[$i]}" "${array2[$i]}" )
done
I've found more common the case where I want to zip two arrays into two columns. This isn't as natively Zsh as the "RTLinuxSW" answer, but for this case, I use paste.
% tabs 16
% paste <(print -l $array1) <(print -l $array2)
one two
three four
five six
seven eight
And then can shove that into another array to get the intended output:
% array3=( `!!`«tab»«tab» )
% print $array3
one two three four five six seven eight