与Python的zip函数等价的Javascript

2024-09-29 00:16:13 发布

您现在位置:Python中文网/ 问答频道 /正文

是否有与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]]

Tags: 函数outputvar数组javascriptziparray等价
3条回答

2016更新:

下面是一个时髦的Ecmascript 6版本:

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

相当于Python的插图:

> 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

(请注意,...语法此时可能会有性能问题,将来也可能会有性能问题,因此如果将第二个答案与可变参数一起使用,则可能需要对其进行性能测试。)


这是一条单行线:

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版本中参数列表是可变的不同。如果您想要所有这些功能,请参见下文。只需要额外的两行代码。

下面将模拟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。多个参数版本),那么zip就不再是它自己的逆了。要模拟Python中的zip(*[...])习惯用法,当您想要反转zip函数或类似地希望将可变数量的列表作为输入时,您需要执行zip.apply(this, [...])


附录

要使此句柄成为任何可iterable(例如,在Python中,可以对字符串、范围、映射对象等使用zip),可以定义以下内容:

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

但是,如果您在下面的way中编写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]]

(或者,如果您已经编写了Python风格的函数,则可以使用该函数。最终,您将能够使用ECMAScript数组理解或生成器。)

查看库Underscore

Underscore provides over 100 functions that support both your favorite workaday functional helpers: map, filter, invoke — as well as more specialized goodies: function binding, javascript templating, creating quick indexes, deep equality testing, and so on.

–说是谁创造了它

我最近开始专门为^{}函数使用它,它给我留下了很好的第一印象。我正在使用jQuery和CoffeeScript,而且它与它们非常匹配。下划线就在它们离开的地方出现,到目前为止它还没有让我失望。哦,顺便说一下,它只缩小了3kb。

看看吧。

除了ninjagecko出色而全面的回答之外,将两个JS数组压缩成一个“元组模拟”只需要:

//Arrays: aIn, aOut
Array.prototype.map.call( aIn, function(e,i){return [e, aOut[i]];})

说明:
由于Javascript没有tuples类型,因此元组、列表和集合的函数在语言规范中不是高优先级的。
否则,可以通过Array map in JS >1.6直接访问类似的行为。(map实际上,在许多>;JS 1.4引擎中,尽管没有指定,JS引擎制造商通常都会实现它) 与Python的zipizip,。。。结果来自map的函数样式,因为map需要一个函数参数。此外,它是Array-实例的函数。如果输入的额外声明有问题,则可以使用Array.prototype.map

示例:

_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)

相关性能:

for循环上使用map-循环:

见:What is the most efficient way of merging [1,2] and [7,8] into [[1,7], [2,8]]

zip tests

注意:基类型(如falseundefined)不具有原型对象层次结构,因此不公开toString函数。因此,这些在输出中显示为空。
由于parseInt的第二个参数是基数/数字基数,要将数字转换为基数,并且由于map将索引作为第二个参数传递给其参数函数,因此使用包装函数。

相关问题 更多 >