Reputation: 8520
Given a number of different sized Arrays:
let allArrays = [ [1, 2, 3], [a, b], [100, 101, 102, 103] ]
I want to take the first element from each array, then the second element from each array, and so on:
let finalArray = [ 1, a, 100, 2, b, 101, 3, 102, 103 ]
My current, naïve solution is to simply loop through allArrays
until allArrays.flat()
is empty, building a new array on the way:
let arr = [ [1, 2, 3], ['a', 'b'], [100, 101, 102, 103] ]
const new_arr = []
while (arr.flat().length) {
for (let sub_arr of arr) {
if (sub_arr.length) {
new_arr.push(sub_arr.shift())
}
}
}
new_arr
// [ 1, 'a', 100, 2, 'b', 101, 3, 102, 103 ]
This strikes me a quite inefficient. What would be the best way to go about this?
Edit to clarify what I'm looking for: Some of the arrays can sometimes be thousands of elements long, and the code is run in the frontend, so I'm searching for a method that is fast.
Also, the lengths and combinations of lengths vary considerably, so rather than optimizing for a single scenario, I'm looking for a way that will be guaranteed to be reasonably fast no matter how the arrays look.
Upvotes: 0
Views: 90
Reputation: 11600
If arrays are mostly the same length, find max length and iterate over the arrays
:
let
arrays = [
[1, 2, 3],
['a', 'b'],
[100, 101, 102, 103]
];
let maxLength = 0;
let result = [];
for (let i = 0; i < arrays.length; i++) {
let len = arrays[i].length;
if (len) {
maxLength < len && (maxLength = len);
result.push(arrays[i][0]);
}
}
for (let i = 1; i < maxLength; i++) {
for (let j = 0; j < arrays.length; j++) {
if (i < arrays[j].length) {
result.push(arrays[j][i]);
}
}
}
console.log(...result);
If arrays are of much different lengths, create an auxiliary array with arrays' indices that have at least a given length:
let
arrays = [
[1, 2, 3],
['a', 'b'],
[100, 101, 102, 103]
];
let arrsToIterate = [];
let result = [];
for (let i = 0; i < arrays.length; i++) {
let len = arrays[i].length;
if (len) {
result.push(arrays[i][0]);
if (len > 1) {
arrsToIterate.push(i);
}
}
}
let idx = 1;
while (arrsToIterate.length) {
for (let i = 0; i < arrsToIterate.length; i++) {
let arr = arrays[arrsToIterate[i]];
if (idx < arr.length) {
result.push(arr[idx]);
} else {
arrsToIterate.splice(i, 1);
i--;
}
}
idx++;
}
console.log(...result);
Upvotes: 1
Reputation: 386560
You could reduce the arrays and flat later.
let
arrays = [[1, 2, 3], ['a', 'b'], [100, 101, 102, 103]]
result = arrays
.reduce((r, array) => {
array.forEach((v, i) => (r[i] ??= []).push(v));
return r;
}, [])
.flat();
console.log(...result);
Upvotes: 3