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.
-
3Note that array map() is not supported in IE8, if that is a problem. Polyfill here developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…TimHayes– TimHayes2014年02月25日 13:37:43 +00:00Commented Feb 25, 2014 at 13:37
-
21This question is NOT a duplicate as it only asks for 2 arrays to be zipped instead of N arrays. Thus it is a special case for which there are specialized, more performant solutions.le_m– le_m2016年06月04日 00:52:47 +00:00Commented Jun 4, 2016 at 0:52
-
Just to say, the zip analogy comes from pythonMatt– Matt2024年09月15日 08:26:04 +00:00Commented Sep 15, 2024 at 8:26
-
2@Matt Is there any source of it? Haskell, Elixir, Scala, basically most of functional programming languages have had zip() for very long time. I doubt Python is its origin?jeff pentagon– jeff pentagon2025年02月26日 21:46:13 +00:00Commented Feb 26, 2025 at 21:46
7 Answers 7
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)
13 Comments
currentvalue, index, arraya is longer) or will omit some entries (if b is longer).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]]
8 Comments
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 array
const result = [...zip(a, b)]
// or lazy generate the values
for (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 iterables
const 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 array
const result = [...zip(a, new Set(b))];
// or lazy generate the values
for (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 anyIterableto an array and then use the first function.
Comments
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)
Comments
If you don't mind using lodash, you can use its zip method for this purpose:
import zip from 'lodash/zip' // or require
const a = [1, 2, 3]
const b = ['a', 'b', 'c']
const result = zip(a, b)
// [[1, 'a'], [2, 'b'], [3, 'c']]
Note: You can zip more than 2 arrays.
If you need a custom operation on the elements, you can use zipWith.
Comments
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);
Comments
Zip function for 2D arrays
Here is a function that zips multiple arrays. However, It only works with 2D arrays only.
function zip(listOfLists) {
return listOfLists[0].map((value, index) => {
let result = [];
for(let i=0; i <= listOfLists.length-1 ; i++){
result[i] = listOfLists[i][index]
}
return result;
});
}
This is how you run it.
console.log(
zip(
[[1, 2, 3],
[4, 5, 6],
[7, 8, 9]]
)
);