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]]
当前回答
python zip函数的生成器方法。
function* zip(...arrs){
for(let i = 0; i < arrs[0].length; i++){
a = arrs.map(e=>e[i])
if(a.indexOf(undefined) == -1 ){yield a }else{return undefined;}
}
}
// use as multiple iterators
for( let [a,b,c] of zip([1, 2, 3, 4], ['a', 'b', 'c', 'd'], ['hi', 'hello', 'howdy', 'how are you']) )
console.log(a,b,c)
// creating new array with the combined arrays
let outputArr = []
for( let arr of zip([1, 2, 3, 4], ['a', 'b', 'c', 'd'], ['hi', 'hello', 'howdy', 'how are you']) )
outputArr.push(arr)
其他回答
不是Javascript本身内置的。一些常见的Javascript框架(如Prototype)提供了一个实现,或者你也可以自己编写。
原始答案(见下文更新)
我修改了flm的漂亮答案,以获取任意数量的数组:
函数* zip(数组,I = 0) { 虽然(我< Math.min(…arrays.map(({长度})= >长度))){ 收益率数组。Map ((arr, j) => arr[j <数组。长度- 1 ?I: i++]) } }
更新后的答案
正如Tom Pohl所指出的,这个函数不能处理数组中有假值的数组。下面是一个更新/改进的版本,可以处理任何类型和长度不等的数组:
函数* zip(数组,I = 0) { 虽然(我< Math.min(…arrays.map (arr = > arr.length))) { 收益率数组。Map ((arr, j) => arr[j <数组。长度- 1 ?I: i++]) } } Const arr1 = [false,0,1,2] Const arr2 = [100,null,99,98,97] Const arr3 = [7,8,undefined,"monkey","banana"] console.log(…zip ([arr1、arr2 arr3)))
除了ninjagecko出色而全面的回答外,将两个js数组压缩成“元组模拟”所需要的是:
//Arrays: aIn, aOut
Array.prototype.map.call( aIn, function(e,i){return [e, aOut[i]];})
Explanation: Since Javascript doesn't have a tuples type, functions for tuples, lists and sets wasn't a high priority in the language specification. Otherwise, similar behavior is accessible in a straightforward manner via Array map in JS >1.6. (map is actually often implemented by JS engine makers in many >JS 1.4 engines, despite not specified). The major difference to Python's zip, izip,... results from map's functional style, since map requires a function-argument. Additionally it is a function of the Array-instance. One may use Array.prototype.map instead, if an extra declaration for the input is an issue.
例子:
_tarrin = [0..constructor, function(){}, false, undefined, '', 100, 123.324,
2343243243242343242354365476453654625345345, 'sdf23423dsfsdf',
'sdf2324.234dfs','234,234fsf','100,100','100.100']
_parseInt = function(i){return parseInt(i);}
_tarrout = _tarrin.map(_parseInt)
_tarrin.map(function(e,i,a){return [e, _tarrout[i]]})
结果:
//'('+_tarrin.map(function(e,i,a){return [e, _tarrout[i]]}).join('),\n(')+')'
>>
(function Number() { [native code] },NaN),
(function (){},NaN),
(false,NaN),
(,NaN),
(,NaN),
(100,100),
(123.324,123),
(2.3432432432423434e+42,2),
(sdf23423dsfsdf,NaN),
(sdf2324.234dfs,NaN),
(234,234fsf,234),
(100,100,100),
(100.100,100)
相关的性能:
使用map over for loops:
请参阅:将[1,2]和[7,8]合并为[[1,7],[2,8]的最有效方法是什么
注意:基本类型如false和undefined不具有原型对象层次结构,因此不公开toString函数。因此,这些在输出中显示为空。 由于parseInt的第二个参数是基数/数字基数,要将数字转换为基数/数字基数,并且由于map将索引作为第二个参数传递给它的参数函数,因此使用包装器函数。
ES2020最短变体:
function * zip(arr1, arr2, i = 0) {
while(arr1[i] || arr2[i]) yield [arr1[i], arr2[i++]].filter(x => !!x);
}
[ ...zip(arr1, arr2) ] // result
我不是一个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的人,所以这些不是最优雅的解决方案,但它们对我来说是可读的。