3

We have an Array of arrays, which we want to interleave into a single array: i.e:

masterArray = [[1, 2, 3], ['c', 'd', 'e']] => [1, 'c', 2, 'd', 3, 'e'],

if arrays are not of equal length, pad it to the longest innerArray's length.

i.e [1, 2, 3], [4, 5]) => [1, 4, 2, 5, 3, null]

I've satisfied this condition with the case of 2 arrays, however if the case is more than that. I struggle to form a strategy on dealing with more than 2.

[1, 2, 3], [4, 5, 6], [7, 8, 9] => [1, 4, 7, 2, 5, 8, 3, 6, 9]

function interleave(...masterArray) {
  let rtnArray = [];
  let longestArrayPosition = getLongestArray(masterArray);
  let longestInnerArrayLength = masterArray[longestArrayPosition].length; 
  padAllArraysToSameLength(masterArray, longestInnerArrayLength); //pad uneven length arrays
  
  masterArray[0].forEach((firstArrayNum, index) => {
    const secondArrayNum = masterArray[1][index];
    rtnArray.push(firstArrayNum);
    rtnArray.push(secondArrayNum);
  });

  return rtnArray;
}

function getLongestArray(masterArray) {
  return masterArray
    .map(a=>a.length)
    .indexOf(Math.max(...masterArray.map(a=>a.length)));
}

function padAllArraysToSameLength(masterArray, maxLength) {
  return masterArray.forEach(arr => {
    if (arr != maxLength) {
      while(arr.length != maxLength) {
        arr.push(null);
      }
    }
  })
}
hello world
  • 306
  • 1
  • 6
  • 28

2 Answers2

4

Use Array.from() to transpose the array of arrays (rows => columns and vice versa), and fill in the missing places with null. Flatten the tramsposed arrays of arrays with Array.flat():

const fn = arr => Array.from({ 
    length: Math.max(...arr.map(o => o.length)), // find the maximum length
  },
  (_, i) => arr.map(r => r[i] ?? null) // create a new row from all items in same column or substitute with null
).flat() // flatten the results

const arr = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]

const result = fn(arr)

console.log(result)
Ori Drori
  • 183,571
  • 29
  • 224
  • 209
  • what is the underscore and double question mark? – hello world Feb 03 '21 at 23:28
  • 1
    The underscore is a placeholder for the first param (the value), which is always `undefined` in this case, and not needed. The `??` is called [Nullish coalescing operator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Nullish_coalescing_operator), and it will return the right hand value (`null` in this case) if the left side is `null` or `undefined` (which is the case if the index doesn't exist on the current array). This allows us to replace `undefined`, but not 0 with `null`. – Ori Drori Feb 03 '21 at 23:35
  • 1
    a clever/creative solution! nice use of FP style coding too, only consts. – wide_eyed_pupil Apr 29 '22 at 04:51
1

You can do this for any number of arrays with two nested forEach statements:

let arr1 = [[1,2,3],[4,5]]
let arr2 = [[1,2,3], [4,5,6], [7,8,9]]
let arr3 = [[1,2,3,4], [4,5,6], [7,8,9], [10,11,12]]

function interLeaveArrays(mainArr){
  let maxLen = Math.max(...mainArr.map(arr => arr.length))
  mainArr.forEach(arr => {
    let lenDiff = maxLen - arr.length
    for(let i=lenDiff; i>0; i--){
      arr.push(null)
    }
  })
  
  let newArr = []
  mainArr.forEach((arr, idx1) => {
    arr.forEach((el, idx2) => {
      newArr[idx2 * mainArr.length + idx1] = el
    })
  })
  return newArr
}

console.log(interLeaveArrays(arr1))
console.log(interLeaveArrays(arr2))
console.log(interLeaveArrays(arr3))
symlink
  • 11,984
  • 7
  • 29
  • 50
  • how did you come up with: idx2 * mainArr.length + idx1 to be the iterated value in the double forEach? – hello world Feb 03 '21 at 23:41
  • 1
    @helloworld since the elements are interleaved, each one needs to be placed according to their position in the array of arrays (`idx2 * mainArr.length`) plus their position within their own array (`+ idx1`) – symlink Feb 03 '21 at 23:45