Javascript 相当于 Python 的 zip 函数 [英] Javascript equivalent of Python's zip function

查看:31
本文介绍了Javascript 相当于 Python 的 zip 函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

是否有与 Python 的 zip 函数等效的 javascript 函数?也就是说,给定多个长度相等的数组,创建一个成对数组.

例如,如果我有三个看起来像这样的数组:

var array1 = [1, 2, 3];var array2 = ['a','b','c'];var array3 = [4, 5, 6];

输出数组应该是:

var 输出数组:[[1,'a',4], [2,'b',5], [3,'c',6]]

解决方案

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[0]].map((_,c) =>rows.map(row =>row[c]))>zip( ['row0col0', 'row0col1', 'row0col2'] ,['row1col0', 'row1col1', 'row1col2'] );//注意 zip(row0,row1),而不是 zip(matrix)与上面相同的答案

(请注意,... 语法此时可能会出现性能问题,并且可能在将来出现,因此如果您使用带有可变参数的第二个答案,您可能需要进行性能测试它.也就是说,它已经很长时间没有出现在标准中了.)

如果您想在字符串上使用它,请务必注意附录(也许现在有更好的方法可以使用 es6 迭代器来做到这一点).


这是一个单线:

function zip(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]]]//如果您认为以下是有效的返回值://>压缩([])//[]//然后你可以对它进行特殊处理,或者只是这样做//返回 arrays.length==0 ?[] : 数组[0].map(...)


以上假设数组的大小应该相同.它还假设您传入一个列表参数列表,这与参数列表是可变参数的 Python 版本不同.如果您想要所有这些功能",请参见下文.它只需要大约 2 行额外的代码.

以下内容将在数组大小不同的边缘情况下模仿 Python 的 zip 行为,默默地假装数组的较长部分不存在:

function zip() {var args = [].slice.call(arguments);var shortest = args.length==0 ?[] : args.reduce(function(a,b){返回 a.length

这将模仿 Python 的 itertools.zip_longest 行为,在未定义数组的地方插入 undefined:

function zip() {var args = [].slice.call(arguments);var 最长 = args.reduce(function(a,b){返回 a.length>b.length ?一:二}, []);返回最长的地图(函数(_,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 不再是它自己的逆版本.要模仿 Python 中的 zip(*[...]) 习惯用法,您需要在需要时执行 zip.apply(this, [...])反转 zip 函数,或者如果您希望类似地将可变数量的列表作为输入.


附录:

为了使这个处理任何可迭代的(例如,在 Python 中,您可以在字符串、范围、地图对象等上使用 zip),您可以定义以下内容:

function iterView(iterable) {//返回一个相当于可迭代对象的数组}

但是,如果您以以下方式编写zip,即使这样也不会必要的:

function zip(arrays) {返回 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]]

(或者,如果您已经编写过 Python 风格的函数,也可以使用 range(...) .最终,您将能够使用 ECMAScript 数组推导式或生成器.)>

Is there a javascript equivalent of Python's zip function? That is, given multiple arrays of equal lengths create an array of pairs.

For instance, if I have three arrays that look like this:

var array1 = [1, 2, 3];
var array2 = ['a','b','c'];
var array3 = [4, 5, 6];

The output array should be:

var output array:[[1,'a',4], [2,'b',5], [3,'c',6]]

解决方案

2016 update:

Here's a snazzier Ecmascript 6 version:

zip= rows=>rows[0].map((_,c)=>rows.map(row=>row[c]))

Illustration equiv. to Python{zip(*args)}:

> zip([['row0col0', 'row0col1', 'row0col2'],
       ['row1col0', 'row1col1', 'row1col2']]);
[["row0col0","row1col0"],
 ["row0col1","row1col1"],
 ["row0col2","row1col2"]]

(and FizzyTea points out that ES6 has variadic argument syntax, so the following function definition will act like python, but see below for disclaimer... this will not be its own inverse so zip(zip(x)) will not equal x; though as Matt Kramer points out zip(...zip(...x))==x (like in regular python zip(*zip(*x))==x))

Alternative definition equiv. to 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

(Do note that the ... syntax may have performance issues at this time, and possibly in the future, so if you use the second answer with variadic arguments, you may want to perf test it. That said it's been quite a while since it's been in the standard.)

Make sure to note the addendum if you wish to use this on strings (perhaps there's a better way to do it now with es6 iterables).


Here's a oneliner:

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(...)


The above assumes that the arrays are of equal size, as they should be. It also assumes you pass in a single list of lists argument, unlike Python's version where the argument list is variadic. If you want all of these "features", see below. It takes just about 2 extra lines of code.

The following will mimic Python's zip behavior on edge cases where the arrays are not of equal size, silently pretending the longer parts of arrays don't exist:

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()
// []

This will mimic Python's itertools.zip_longest behavior, inserting undefined where arrays are not defined:

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()
// []

If you use these last two version (variadic aka. multiple-argument versions), then zip is no longer its own inverse. To mimic the zip(*[...]) idiom from Python, you will need to do zip.apply(this, [...]) when you want to invert the zip function or if you want to similarly have a variable number of lists as input.


addendum:

To make this handle any iterable (e.g. in Python you can use zip on strings, ranges, map objects, etc.), you could define the following:

function iterView(iterable) {
    // returns an array equivalent to the iterable
}

However if you write zip in the following way, even that won't be necessary:

function zip(arrays) {
    return Array.apply(null,Array(arrays[0].length)).map(function(_,i){
        return arrays.map(function(array){return array[i]})
    });
}

Demo:

> JSON.stringify( zip(['abcde',[1,2,3,4,5]]) )
[["a",1],["b",2],["c",3],["d",4],["e",5]]

(Or you could use a range(...) Python-style function if you've written one already. Eventually you will be able to use ECMAScript array comprehensions or generators.)

这篇关于Javascript 相当于 Python 的 zip 函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆