Chad
Chad

Reputation: 71

Combine two arrays in a "zipping" fashion - JavaScript

So, I've been thinking of just some little practice things that I could do with arrays in JavaScript. I came across the idea of combining two arrays in a "zipping" fashion (arrayA[0], arrayB[0], arrayA[1], arrayB[1]...) and so on and so forth. Anything left over in a potential longer array would be tacked onto the end.

I've searched stackoverflow - reason I'm asking is I'm currently in introductory programming courses, so we don't really know a whole lot of "things" we can do with JavaScript. Would like to see a solution with "simple" methods if possible!

I've currently got the alternate fashion going, but I can't seem to get the last part of tacking the remaining parts of the array to the very end.

function alternatingMerge(array1, array2)
//this function will merge two different arrays in an alternating fashion
//i.e = array1[0], array2[0], array1[1], array2[1], array1[2], array2[2], ... , etc
{
    var mergedArray;
    var i; // while loop counter
    var j; // 
    var k; // 
    var arrayLengths;

    arrayLengths = array1.length + array2.length;
    i = 0; // 
    j = 0; // ARRAY1 COUNTER
    k = 0; // ARRAY2 COUNTER
    mergedArray = new Array(arrayLengths);
    //window.alert(mergedArray);

    while (i < arrayLengths)
    {
        if (i%2 === 0)
        {
            mergedArray[i] = array2[j];
            j = j + 1;
        }
        else
        {
            mergedArray[i] = array1[k];
            k = k + 1;
        }
        i = i + 1;
    }
    return mergedArray;
}

I feel like it's simple stuff but some help would be appreciated!

Upvotes: 4

Views: 4412

Answers (6)

omikes
omikes

Reputation: 8513

Here is a small but effective weaving function for two arrays of any size using ES6 (modern browsers):

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

const array1 = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
const array2 = ['A', 'B', 'C', 'D', 'E'];

console.log(JSON.stringify(w(array1, array2)));

Explanation:

The variable w is set to this short recursive function:

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

I'll explain it piece by piece since there's no room for comments.

(a, b) => - For two input arrays, a and b.

a.length - Check if the first array is not empty.

? [___] - If it is not empty, return an array.

a[0], - Make the first item in this array the same first item from the first array.

...w(b, a.slice(1)) - Fill the rest of the array with the results of this same function using array b for the first parameter and everything but the first item of array a for the second parameter.

: b - Otherwise, if the first array is empty, return array b.

What it ends up doing is switching between the first and second arrays, removing the first item from that array and passing it back recursively to the result array. It does this until one of the arrays has no items left, at which point the rest of the other array is returned and added to the end of the result.


With a few adjustments, it can rotate through any number of arrays. This version runs basically the same way, except the first array gets a default value to handle no arguments being fed in, and the second parameter handles multiple arrays instead of one. Also, before checking the length of array a, it counts the arrays in b to see if there are any arrays left to rotate through. If there aren't any, array a is returned. If there are arrays left, but a is empty, the results of the recursive function are returned using the remaining arrays as its parameters.

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

const array1 = [1, 2];
const array2 = '♦♡♣♤♥♢';
const array3 = ['A', 'B', 'C'];
const array4 = ['😊', '😔', '😠'];
const array5 = [null, NaN, undefined];

const 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(w()));
console.log(stringify(w(array1)));
console.log(stringify(w(array1, array2)));
console.log(stringify(w(array1, array2, array3)));
console.log(stringify(w(array1, array2, array3, array4)));
console.log(stringify(w(array1, array2, array3, array4, array5)));

The stringify function is something I added to correct for JSON.stringify converting NaN and undefined into null. It does not effect the way the weaving function works.

Upvotes: 9

jo_va
jo_va

Reputation: 13964

Here is a short way to do it using Array.from(), Array.flat() and Array.filter():

const zip = (a, b) => Array.from( // create an array
    { length: Math.max(a.length, b.length) }, // as long as the longest of a and b
    (_, i) => [a[i], b[i]] // fill it with pairs from a and b
  ).flat().filter(x => x !== undefined); // then flatten the pairs and remove undefined entries

console.log(...zip([1, 2, 3, 4, 5, 6, 7, 8], ['a', 'b', 'c', 'd']));
console.log(...zip([1, 2, 3, 4], ['a', 'b', 'c', 'd', 'e', 'f', 'g']));
console.log(...zip([1, 2, 4, 5], []));
console.log(...zip([], ['a', 'b', 'c', 'd']));

Upvotes: 2

Alien426
Alien426

Reputation: 1257

var aOne = [1,3,5,7,9,11], aTwo = [2,4,6,8], aResult = [];
while (Math.max(aOne.length, aTwo.length) > 0)
  aResult.push(aOne.shift(), aTwo.shift());
document.writeln('aResult: ' + JSON.stringify(aResult.filter(Boolean)));
// aResult: [1,2,3,4,5,6,7,8,9,11]

The .filter(Boolean) is necessary to remove null values resulting from one of the arrays being empty before the other.

Upvotes: 0

g.d.d.c
g.d.d.c

Reputation: 47968

I thought about this for a while and this is what I came up with. It also supports arbitrary numbers of arrays as input like some of the other answers.

function merge() {
  var result = [];
  for (var i = 0;;++i) {
    var temp = [];
    for (var j = 0; j < arguments.length; ++j) {
      var atPos = arguments[j].slice(i, i+1);
      if (atPos.length) {
        temp.push(result.push(atPos[0]));
      }
    }
    if (temp.length == 0) {
      return result;
    }
  }
}

Upvotes: 0

Kenan Banks
Kenan Banks

Reputation: 211922

Here's a quick take...

// Takes an arbitrary number of arrays as arguments
function zip() {
   var merged = [], index = 0, cont, i;
   do {
      cont = false;
      for (var i=0; i<arguments.length; i++) {
         A = arguments[i];
         if (index < A.length) {   
            cont = true;
            merged.push(A[index]);
         }
      }
      index++;
   } while (cont);
   return merged;
}

merged = zip([1,3,5,7,9,11], [2,4,6,8]);
// [1, 2, 3, 4, 5, 6, 7, 8, 9, 11]

merged = zip([1, 4, 7], [2, 5, 8], [3, 6, 9])
// [1, 2, 3, 4, 5, 6, 7, 8, 9]

Upvotes: 2

jfriend00
jfriend00

Reputation: 707158

How about this:

function mergeAlternating(array1, array2) {
    var mergedArray = [];

    for (var i = 0, len = Math.max(array1.length, array2.length); i < len; i++) {
        if (i < array1.length) {
            mergedArray.push(array1[i]);
        }
        if (i < array2.length) {
            mergedArray.push(array2[i]);
        }
    }
    return mergedArray;
}

Upvotes: 4

Related Questions