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]]
当前回答
ES2020最短变体:
function * zip(arr1, arr2, i = 0) {
while(arr1[i] || arr2[i]) yield [arr1[i], arr2[i++]].filter(x => !!x);
}
[ ...zip(arr1, arr2) ] // result
其他回答
惰性生成器解决方案的一个变体:
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)))]
和@Brandon一样,我推荐Underscore的zip功能。但是,它的作用类似zip_longest,根据需要附加未定义的值以返回最长输入的长度。
我使用mixin方法用zipshort扩展下划线,它的作用类似于Python的zip,基于库自己的zip源代码。
你可以在你的普通JS代码中添加以下代码,然后像调用下划线一样调用它:_。zipShortest ([1, 2, 3], [a])返回[[1,' ']],例如。
// Underscore library addition - zip like python does, dominated by the shortest list
// The default injects undefineds to match the length of the longest list.
_.mixin({
zipShortest : function() {
var args = Array.Prototype.slice.call(arguments);
var length = _.min(_.pluck(args, 'length')); // changed max to min
var results = new Array(length);
for (var i = 0; i < length; i++) {
results[i] = _.pluck(args, "" + i);
}
return results;
}});
原始答案(见下文更新)
我修改了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)))
ES2020最短变体:
function * zip(arr1, arr2, i = 0) {
while(arr1[i] || arr2[i]) yield [arr1[i], arr2[i++]].filter(x => !!x);
}
[ ...zip(arr1, arr2) ] // result
我在纯JS中尝试了一下,想知道上面发布的插件是如何完成这项工作的。这是我的结果。首先我要说的是,我不知道这在IE和类似的软件中会有多稳定。这只是一个快速的模型。
init(); function init() { var one = [0, 1, 2, 3]; var two = [4, 5, 6, 7]; var three = [8, 9, 10, 11, 12]; var four = zip(one, two, one); //returns array //four = zip(one, two, three); //returns false since three.length !== two.length console.log(four); } function zip() { for (var i = 0; i < arguments.length; i++) { if (!arguments[i].length || !arguments.toString()) { return false; } if (i >= 1) { if (arguments[i].length !== arguments[i - 1].length) { return false; } } } var zipped = []; for (var j = 0; j < arguments[0].length; j++) { var toBeZipped = []; for (var k = 0; k < arguments.length; k++) { toBeZipped.push(arguments[k][j]); } zipped.push(toBeZipped); } return zipped; }
虽然不是无懈可击,但还是很有趣。