5

I had an whiteboard task that stumped me in the interview, however I have written a solution and wondered if anyone has improvements on it as I'm iterating which the interviewer said not to. The two arrays must be merged with the order being array1[0], array2[0], array1[1], array2[1]... (see expectedResult) etc

const options = [[1, 12, 5], ["a", "b", "c", "d", "e"]]
const expectedResult = [1, "a", 12, "b", 5, "c", "d", "e"]

function mergeArrays(first, second) {
  let returnArray = []
  
  first.forEach((value, key) => {
    returnArray.push(value)
    if (second[key]) returnArray.push(second[key])
    if (!first[key + 1] && second[key + 1]) {
      returnArray.push(
        ...second.slice(key + 1, second.length)
      )
    }
  })
  return returnArray
}

const result = mergeArrays(options[0], options[1])
console.log(result.toString() === expectedResult.toString(), result)
azz0r
  • 3,283
  • 7
  • 42
  • 85
  • What does 'looping' mean? You can use any type of loop? Wha? – mattsven Jan 12 '17 at 09:17
  • So in the interview I suggested something similar to the code above, I was then asked about performance if there were thousands in items in the arrays and it was implied I should avoid foreach/while etc – azz0r Jan 12 '17 at 11:25

4 Answers4

3

I go the classic way, with a while loop, because it minimize the checks inside of the loop and appends without another check just the rest of one of the arrays.

function mergeArrays(first, second) {
    var min = Math.min(first.length, second.length),
        i = 0,
        result = [];

    while (i < min) {
        result.push(first[i], second[i]);
        ++i;
    }
    return result.concat(first.slice(min), second.slice(min));
}

const options = [[1, 12, 5], ["a", "b", "c", "d", "e"]];

console.log(mergeArrays(...options));
.as-console-wrapper { max-height: 100% !important; top: 0; }
Nina Scholz
  • 376,160
  • 25
  • 347
  • 392
3

With reduce (as an alternative to the classical for/while loop control structures)

const options = [[1, 12, 5], ["a", "b", "c", "d", "e"]];
const expectedResult = [1, "a", 12, "b", 5, "c", "d", "e"]

// a is the accumulator
// cV, cI are resp. current value and current index
result = options[0].reduce(function (a, cV, cI) {
    return a.concat([cV,options[1][cI]]);
},[]);


result = result.concat(options[1].splice(options[0].length));
console.log(result.toString() === expectedResult.toString(), result)

At each step two elements are added to the accumulator array a using concat.

user2314737
  • 27,088
  • 20
  • 102
  • 114
  • Noticed the suggestions with loops got votes over this, would love to know peoples reasoning for that. (no judgement on the loop replies, would just like to understand) – azz0r Jan 12 '17 at 11:23
  • @gkoul sure, for array `x` just add in step `a.concat([cV, options[1][cI], x[cI]])` – user2314737 Nov 01 '20 at 23:58
2

Instead of using value in if conditions , check for length of array.

Problems I see in code are at conditions

   if (second[key]) returnArray.push(second[key])
   // will not run if second[key] is 0,null,undefined.
   if (!first[key + 1] && second[key + 1]) 
   // will produce unwanted result if value reference is 0,null,undefined.

so instead, check for length would produce better result So the condition

    if (second[key]) returnArray.push(second[key]) 

can be changed into

   if( second.length > key) returnArray.push(second[key]) 
user1536841
  • 146
  • 1
  • 6
2

You can use a recursive zipping function, using spread to feed an array of two into it as its parameters:

var z = (a, b) => a.length ? [a[0], ...z(b, a.slice(1))] : b;

var options = 
[
    [1, 12, 5], 
    ["a", "b", "c", "d", "e"]
];

var expectedResult = z(...options);
console.log(JSON.stringify(expectedResult));

or for any number of array inputs:

var z = (a = [], ...b) => 
    b.length ? a.length ? [a[0], ...z(...b, a.slice(1))] : z(...b) : a;

var options = 
[
    [1, 2], 
    '♦♡♣♤♥♢', 
    ['A', 'B', 'C'], 
    ['', '', ''], 
    [null, NaN, undefined]
];

var expectedResult = z(...options);
var stringify = (o) => JSON.stringify(o, (k, v) => v === undefined ? '__undefined__' : v !== v ? '__NaN__' : v).replace(/"__undefined__"/g, 'undefined').replace(/"__NaN__"/g, 'NaN');
console.log(stringify(expectedResult));
omikes
  • 8,064
  • 8
  • 37
  • 50