javascript中是否有类似于Python的zip函数?也就是说,给定多个相等长度的数组,创建一个由对组成的数组。
例如,如果我有三个这样的数组:
var array1 = [1, 2, 3];
var array2 = ['a','b','c'];
var array3 = [4, 5, 6];
输出数组应该是:
var outputArray = [[1,'a',4], [2,'b',5], [3,'c',6]]
javascript中是否有类似于Python的zip函数?也就是说,给定多个相等长度的数组,创建一个由对组成的数组。
例如,如果我有三个这样的数组:
var array1 = [1, 2, 3];
var array2 = ['a','b','c'];
var array3 = [4, 5, 6];
输出数组应该是:
var outputArray = [[1,'a',4], [2,'b',5], [3,'c',6]]
当前回答
惰性生成器解决方案的一个变体:
function* iter(it) { yield* it; } function* zip(...its) { its = its.map(iter); while (true) { let rs = its.map(it => it.next()); if (rs.some(r => r.done)) return; yield rs.map(r => r.value); } } for (let r of zip([1,2,3], [4,5,6,7], [8,9,0,11,22])) console.log(r.join()) // the only change for "longest" is some -> every function* zipLongest(...its) { its = its.map(iter); while (true) { let rs = its.map(it => it.next()); if (rs.every(r => r.done)) return; yield rs.map(r => r.value); } } for (let r of zipLongest([1,2,3], [4,5,6,7], [8,9,0,11,22])) console.log(r.join())
这是python经典的“n-group”习语zip(*[iter(a)]*n):
triples = [...zip(...Array(3).fill(iter(a)))]
其他回答
这将从Ddi基于迭代器的答案中删除一行:
function* zip(...toZip) {
const iterators = toZip.map((arg) => arg[Symbol.iterator]());
const next = () => toZip = iterators.map((iter) => iter.next());
while (next().every((item) => !item.done)) {
yield toZip.map((item) => item.value);
}
}
我创建了一个简单的函数,通过一个选项来提供一个拉链函数
function zip(zipper, ...arrays) {
if (zipper instanceof Array) {
arrays.unshift(zipper)
zipper = (...elements) => elements
}
const length = Math.min(...arrays.map(array => array.length))
const zipped = []
for (let i = 0; i < length; i++) {
zipped.push(zipper(...arrays.map(array => array[i])))
}
return zipped
}
https://gist.github.com/AmrIKhudair/4b740149c29c492859e00f451832975b
与其他类似Python的函数一样,pythonic提供了一个zip函数,其额外的好处是返回一个惰性求值迭代器,类似于Python对应的行为:
import {zip, zipLongest} from 'pythonic';
const arr1 = ['a', 'b'];
const arr2 = ['c', 'd', 'e'];
for (const [first, second] of zip(arr1, arr2))
console.log(`first: ${first}, second: ${second}`);
// first: a, second: c
// first: b, second: d
for (const [first, second] of zipLongest(arr1, arr2))
console.log(`first: ${first}, second: ${second}`);
// first: a, second: c
// first: b, second: d
// first: undefined, second: e
// unzip
const [arrayFirst, arraySecond] = [...zip(...zip(arr1, arr2))];
我是Pythonic的作者和维护者
带有生成器的现代ES6示例:
function *zip (...iterables){
let iterators = iterables.map(i => i[Symbol.iterator]() )
while (true) {
let results = iterators.map(iter => iter.next() )
if (results.some(res => res.done) ) return
else yield results.map(res => res.value )
}
}
首先,我们得到一个iterables列表作为迭代器。这通常是透明地发生的,但在这里我们明确地进行,因为我们逐步让步,直到其中一个耗尽。我们检查给定数组中的任何结果(使用.some()方法)是否已耗尽,如果是,则中断while循环。
我不是一个javascript的人,但我觉得这些答案是试图找到最可爱和最聪明的解决方案使用数组。这是很好的,但对于像我这样不每天使用javascript的人来说,这里有一些可能更可读的替代方案。
也许有一种方法可以避免一些可爱而聪明的代码:
function zip(a,b){
// pre-allocate an array to hold the results
rval=Array(Math.max(a.length, b.length));
for(i=0; i<rval.length; i++){
rval[i]=[a[i],b[i]]
}
return rval
}
如果你喜欢生成器:
function* _zip(a,b){
len = Math.max(a.length, b.length) // handle different sized arrays
for(i=0; i<len; i++) { yield [a[i],b[i]] }
}
或者如果你真的想使用Array.map:
function map(a,b){
x = a.length > b.length ? a : b // call map on the biggest array
return x.map((_,i)=>[a[i],b[i]])
}
就像我说的,我不是一个日常使用javascript的人,所以这些不是最优雅的解决方案,但它们对我来说是可读的。