是否有与Python的zip函数等效的JavaScript?也就是说,给定多个相同长度的数组,将创建一个成对的数组。
Python
zip
JavaScript?
例如,如果我有三个看起来像这样的数组:
var array1 = [1, 2, 3]; var array2 = ['a','b','c']; var array3 = [4, 5, 6];
输出数组应为:
var output array:[[1,'a',4], [2,'b',5], [3,'c',6]]
这是一个时髦的Ecmascript 6版本:
zip= rows=>rows[0].map((_,c)=>rows.map(row=>row[c]))
相当于插图。到Python { zip(*args)}:
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))
FizzyTea
zip(zip(x)
zip(...zip(...x))==x(
zip(*zip(*x))==x))
等效定义 到Python { zip}:
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
(请注意,…语法可能在此时以及将来可能会出现性能问题,因此,如果将第二个答案与可变参数一起使用,则可能要进行性能测试。)
这里是一个班轮:
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(...)
上面假设数组的大小相等,应该是相等的。它还假定你传入一个lists参数列表,这与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在未定义数组的地方插入:
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() // []
如果使用最后两个版本(可变变量,也称为多参数版本),则zip不再是其自身的反函数。要模仿zip(*[...])Python中的习惯用法,你需要zip.apply(this, [...])在想要反转zip函数时或者在类似情况下要使用可变数量的列表作为输入时进行操作。
zip(*[...])Python
zip.apply(this, [...])
附录:
要使此句柄具有任何可迭代性(例如,在Python中,你可以zip在字符串,范围,地图对象等上使用),可以定义以下内容:
function iterView(iterable) { // returns an array equivalent to the iterable }
但是,如果你zip以以下方式编写,则甚至没有必要:
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数组推导或生成器。)
range(...)
ECMAScript