I have 2 arrays:

var a = [1, 2, 3]var b = [a, b, c]

What I want to get as a result is:

[[1, a], [2, b], [3, c]]

It seems simple but I just can't figure out.

I want the result to be one array with each of the elements from the two arrays zipped together.

5

Best Answer


Use the map method:

var a = [1, 2, 3]var b = ['a', 'b', 'c']var c = a.map(function(e, i) {return [e, b[i]];});console.log(c)

DEMO

Zip Arrays of same length:

Using Array.prototype.map()

const zip = (a, b) => a.map((k, i) => [k, b[i]]);console.log(zip([1,2,3], ["a","b","c"]));// [[1, "a"], [2, "b"], [3, "c"]]

Zip Arrays of different length:

Using Array.from()

const zip = (a, b) => Array.from(Array(Math.max(b.length, a.length)), (_, i) => [a[i], b[i]]);console.log( zip([1,2,3], ["a","b","c","d"]) );// [[1, "a"], [2, "b"], [3, "c"], [undefined, "d"]]

Using Array.prototype.fill() and Array.prototype.map()

const zip = (a, b) => Array(Math.max(b.length, a.length)).fill().map((_,i) => [a[i], b[i]]);console.log(zip([1,2,3], ["a","b","c","d"]));// [[1, "a"], [2, "b"], [3, "c"], [undefined, "d"]]

Zip Multiple (n) Arrays:

const zip = (...arr) => Array(Math.max(...arr.map(a => a.length))).fill().map((_,i) => arr.map(a => a[i])); console.log(zip([1,2], [3,4], [5,6])); // [[1,3,5], [2,4,6]]

Zipping by leveraging generator functions

You can also use a generator function to zip().

const a = [1, 2, 3]const b = ['a', 'b', 'c']/*** Zips any number of arrays. It will always zip() the largest array returning undefined for shorter arrays.* @param {...Array<any>} arrays */function* zip(...arrays){const maxLength = arrays.reduce((max, curIterable) => curIterable.length > max ? curIterable.length: max, 0);for (let i = 0; i < maxLength; i++) {yield arrays.map(array => array[i]);}}// put zipped result in an arrayconst result = [...zip(a, b)]// or lazy generate the valuesfor (const [valA, valB] of zip(a, b)) {console.log(`${valA}: ${valB}`); }
.as-console-wrapper { max-height: 100% !important; top: 0; }

The above works for any number of arrays and will zip() the longest array so undefined is returned as a value for shorter arrays.

Zipping of all Iterables

Here a function which can be used for all Iterables (e.g. Maps, Sets or your custom Iterable), not just arrays.

const a = [1, 2, 3];const b = ["a", "b", "c"];/*** Zips any number of iterables. It will always zip() the largest Iterable returning undefined for shorter arrays.* @param {...Iterable<any>} iterables*/function* zip(...iterables) {// get the iterator of for each iterablesconst iters = [...iterables].map((iterable) => iterable[Symbol.iterator]());let next = iters.map((iter) => iter.next().value);// as long as any of the iterables returns something, yield a value (zip longest)while(anyOf(next)) {yield next;next = iters.map((iter) => iter.next().value);}function anyOf(arr){return arr.some(v => v !== undefined);}}// put zipped result in aa arrayconst result = [...zip(a, new Set(b))];// or lazy generate the valuesfor (const [valA, valB] of zip(a, new Set(b))) {console.log(`${valA}: ${valB}`);}

Obviously it would also be possible to just use [...Iterable] to transform any Iterable to an array and then use the first function.

Using the reduce method:

const a = [1, 2, 3]const b = ['a', 'b', 'c']var c = a.reduce((acc, curr, ind) => {acc.push([curr, b[ind]]);return acc;}, []);console.log(c)

With forEach method:

const a = [1, 2, 3]const b = ['a', 'b', 'c']const c = [];a.forEach((el, ind) => {c.push([el, b[ind]])});console.log(c)

Providing a solution with imperative programming by a simple for loop.

This performs better when doing the zip operation on huge data sets compared to the convenient array functions like map() and forEach().

Example:

const a = [1, 2, 3];const b = ['a', 'b', 'c'];const result = [];for (let i = 0; i < a.length; i++) {result.push([a[i], b[i]]);}console.log(result);

And if you want a 1 line simpler solution then you can use a library like ramda which has a zip function.

Example:

const a = [1, 2, 3];const b = ['a', 'b', 'c'];const result = R.zip(a, b);console.log(result);