2016 年更新:
这是一个更时髦的 Ecmascript 6 版本:
zip= rows=>rows[0].map((_,c)=>rows.map(row=>row[c]))
插图等价物。 Python{zip(*args)}:
> zip([['row0col0', 'row0col1', 'row0col2'],
['row1col0', 'row1col1', 'row1col2']]);
[["row0col0","row1col0"],
["row0col1","row1col1"],
["row0col2","row1col2"]]
(并且 FizzyTea 指出 ES6 具有可变参数语法,因此以下函数定义将像 python 一样,但请参阅下面的免责声明...这不会是它自己的逆,所以 zip(zip(x)) 不会等于 x ; 虽然正如 Matt Kramer 指出的那样 zip(...zip(...x))==x (就像在常规 python 中一样 zip(*zip(*x))==x))
替代定义等价。 Python{zip}:
> zip = (...rows) => [...rows[0]].map((_,c) => rows.map(row => row[c]))
> zip( ['row0col0', 'row0col1', 'row0col2'] ,
['row1col0', 'row1col1', 'row1col2'] );
// note zip(row0,row1), not zip(matrix)
same answer as above
(请注意,... 语法目前可能存在性能问题,将来也可能存在问题,因此如果您使用带有可变参数的第二个答案,您可能需要对其进行性能测试。也就是说它已经相当有一段时间了,因为它已经在标准中了。)
如果您希望在字符串上使用它,请务必注意附录(也许现在使用 es6 迭代有更好的方法)。
这是一个单线:
function zip(arrays) {
return arrays[0].map(function(_,i){
return arrays.map(function(array){return array[i]})
});
}
// > zip([[1,2],[11,22],[111,222]])
// [[1,11,111],[2,22,222]]]
// If you believe the following is a valid return value:
// > zip([])
// []
// then you can special-case it, or just do
// return arrays.length==0 ? [] : arrays[0].map(...)
以上假设数组大小相同,应该是这样。它还假设您传入一个列表参数列表,这与参数列表是可变参数的 Python 版本不同。 如果您想要所有这些“功能”,请参见下文。它只需要大约 2 行额外的代码。
以下将在数组大小不相等的边缘情况下模仿 Python 的 zip 行为,默默地假装数组的较长部分不存在:
function zip() {
var args = [].slice.call(arguments);
var shortest = args.length==0 ? [] : args.reduce(function(a,b){
return a.length<b.length ? a : b
});
return shortest.map(function(_,i){
return args.map(function(array){return array[i]})
});
}
// > zip([1,2],[11,22],[111,222,333])
// [[1,11,111],[2,22,222]]]
// > zip()
// []
这将模仿 Python 的 itertools.zip_longest 行为,在未定义数组的地方插入 undefined:
function zip() {
var args = [].slice.call(arguments);
var longest = args.reduce(function(a,b){
return a.length>b.length ? a : b
}, []);
return longest.map(function(_,i){
return args.map(function(array){return array[i]})
});
}
// > zip([1,2],[11,22],[111,222,333])
// [[1,11,111],[2,22,222],[null,null,333]]
// > zip()
// []
如果您使用这最后两个版本(variadic aka.multi-argument 版本),那么 zip 不再是它自己的逆。为了模仿 Python 中的 zip(*[...]) 习语,当您想要反转 zip 函数或想要类似地使用可变数量的列表作为输入时,您需要执行 zip.apply(this, [...])。
附录:
要使此句柄可迭代(例如,在 Python 中,您可以在字符串、范围、地图对象等上使用 zip),您可以定义以下内容:
function iterView(iterable) {
// returns an array equivalent to the iterable
}
但是,如果您将zip 写在下面的way 中,那么即使这样也没有必要:
function zip(arrays) {
return Array.apply(null,Array(arrays[0].length)).map(function(_,i){
return arrays.map(function(array){return array[i]})
});
}
演示:
> JSON.stringify( zip(['abcde',[1,2,3,4,5]]) )
[["a",1],["b",2],["c",3],["d",4],["e",5]]
(或者,如果您已经编写了一个 range(...) Python 风格的函数,您也可以使用它。最终您将能够使用 ECMAScript 数组解析或生成器。)