相当于Python的zip函数的Javascript

2020/10/12 14:01 · javascript ·  · 0评论

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

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) => [...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版本的参数列表是可变参数不同。如果需要所有这些“功能”,请参见下文。它只需要多花两行代码。

以下内容将模仿Pythonzip在数组大小不等的极端情况下行为,默默地假装数组的较长部分不存在:

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

如果使用最后两个版本(可变变量,也称为多参数版本),则zip不再是其自身的反函数。为了模仿zip(*[...])Python中习惯用法,您需要zip.apply(this, [...])在想要反转zip函数时或者想要以类似数量的列表作为输入时进行操作。


附录

为了使此句柄变得可迭代(例如,在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数组推导或生成器。)

查看库Underscore

Underscore提供了100多种功能,可同时支持您最喜欢的工作功能助手:映射,过滤器,调用—以及更专业的功能:函数绑定,javascript模板,创建快速索引,深度相等性测试等。

–说出成功的人

我最近开始专门针对该zip()功能使用它,并给人留下了深刻的第一印象。我正在使用jQuery和CoffeeScript,它与它们完美匹配。下划线在他们离开的地方开始,到目前为止,这并没有让我失望。哦,顺便说一下,它只有3kb。

看看这个:

_.zip(['moe', 'larry', 'curly'], [30, 40, 50], [true, false, false]);
// returns [["moe", 30, true], ["larry", 40, false], ["curly", 50, false]]

除了ninjagecko出色而全面的答案外,将两个JS数组压缩为“ tuple-mimic”所需要的一切还包括:

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

说明:

由于Javascript没有
tuples类型,因此在语言规范中,元组,列表和集合的函数并不是高优先级。

否则,可以通过
JS> 1.6中的Array map以直接的方式访问类似的行为map尽管未指定,实际上通常是由JS引擎制造商在许多> JS 1.4引擎中实现的)。

与Python的
zip,,izip...的主要区别来自map的功能风格,因为它map需要一个功能参数。另外,它是Array-instance的函数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)

相关性能:

使用mapover- forloops:

请参阅:将[1,2]和[7,8]合并为[[1,7],[2,8]]的最有效方法是什么

邮编测试

注意:基本类型(例如false和)undefined不构成原型对象层次结构,因此不公开toString函数。因此,这些在输出中显示为空。

作为
parseInt的第二个参数是基数/数字基数,将数字转换为该基数/基数,并且由于map将索引作为第二个参数传递给它的参数函数,因此使用了包装函数。

与其他类似Python的函数一起,pythonic提供了一个zip函数,函数具有返回惰性求值的额外好处Iterator,类似于其Python对应函数的行为

import {zip, zipLongest} from 'pythonic';

const arr1 = ['a', 'b'];
const arr2 = ['c', 'd', 'e'];
for (const [first, second] of zip(arr1, arr2))
    console.log(`first: ${first}, second: ${second}`);
// first: a, second: c
// first: b, second: d

for (const [first, second] of zipLongest(arr1, arr2))
    console.log(`first: ${first}, second: ${second}`);
// first: a, second: c
// first: b, second: d
// first: undefined, second: e

// unzip
const [arrayFirst, arraySecond] = [...zip(...zip(arr1, arr2))];

披露我是Pythonic的作者和维护者

具有生成器的现代ES6示例:

function *zip (...iterables){
    let iterators = iterables.map(i => i[Symbol.iterator]() )
    while (true) {
        let results = iterators.map(iter => iter.next() )
        if (results.some(res => res.done) ) return
        else yield results.map(res => res.value )
    }
}

首先,我们得到一个可迭代的列表iterators这通常是透明地发生的,但是在此我们明确地做到这一点,因为我们一步一步产生,直到用尽其中之一。我们检查.some()给定数组中的任何结果(使用该方法)是否耗尽,如果是,则中断while循环。

Python具有两个功能:zip和itertools.zip_longest。在JS / ES6上的实现是这样的:

在JS / ES6上实现Python的zip

const zip = (...arrays) => {
    const length = Math.min(...arrays.map(arr => arr.length));
    return Array.from({ length }, (value, index) => arrays.map((array => array[index])));
};

结果:

console.log(zip(
    [1, 2, 3, 'a'],
    [667, false, -378, '337'],
    [111],
    [11, 221]
));

[[1,667,111,11]]

console.log(zip(
    [1, 2, 3, 'a'],
    [667, false, -378, '337'],
    [111, 212, 323, 433, '1111']
));

[[1,667,111],[2,错误,212],[3,-378,323],['a','337',433]]

console.log(zip(
    [1, 2, 3, 'a'],
    [667, false, -378, '337'],
    [111],
    []
));

[]

在JS / ES6上实现Python的zip_longest

https://docs.python.org/3.5/library/itertools.html?highlight=zip_longest#itertools.zip_longest

const zipLongest = (placeholder = undefined, ...arrays) => {
    const length = Math.max(...arrays.map(arr => arr.length));
    return Array.from(
        { length }, (value, index) => arrays.map(
            array => array.length - 1 >= index ? array[index] : placeholder
        )
    );
};

结果:

console.log(zipLongest(
    undefined,
    [1, 2, 3, 'a'],
    [667, false, -378, '337'],
    [111],
    []
));

[[

1,667,111
,undefined],[2,false,undefined,undefined],[3,-378,undefined,undefined],['a','337',undefined,undefined]]

console.log(zipLongest(
    null,
    [1, 2, 3, 'a'],
    [667, false, -378, '337'],
    [111],
    []
));

[[1,667,111,null],[2,false,null,null],[3,-378,null,null],['a','337',null,null]]

console.log(zipLongest(
    'Is None',
    [1, 2, 3, 'a'],
    [667, false, -378, '337'],
    [111],
    []
));

[[1,667,111,'Is None'],[2,false,'Is None','Is None'],

[3,-378,'Is None','Is None'],['a ','337','无','无']]

您可以使用ES6使实用程序功能。

const zip = (arr, ...arrs) => {
  return arr.map((val, i) => arrs.reduce((a, arr) => [...a, arr[i]], [val]));
}

// example

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

console.log(zip(array1, array2));                  // [[1, 'a'], [2, 'b'], [3, 'c']]
console.log(zip(array1, array2, array3));          // [[1, 'a', 4], [2, 'b', 5], [3, 'c', 6]]

但是,在上述解决方案中,第一个数组的长度定义了输出数组的长度。

这是您可以对其进行更多控制的解决方案。这有点复杂,但值得。

function _zip(func, args) {
  const iterators = args.map(arr => arr[Symbol.iterator]());
  let iterateInstances = iterators.map((i) => i.next());
  ret = []
  while(iterateInstances[func](it => !it.done)) {
    ret.push(iterateInstances.map(it => it.value));
    iterateInstances = iterators.map((i) => i.next());
  }
  return ret;
}
const array1 = [1, 2, 3];
const array2 = ['a','b','c'];
const array3 = [4, 5, 6];

const zipShort = (...args) => _zip('every', args);

const zipLong = (...args) => _zip('some', args);

console.log(zipShort(array1, array2, array3)) // [[1, 'a', 4], [2, 'b', 5], [3, 'c', 6]]
console.log(zipLong([1,2,3], [4,5,6, 7]))
// [
//  [ 1, 4 ],
//  [ 2, 5 ],
//  [ 3, 6 ],
//  [ undefined, 7 ]]

1. Npm模块: zip-array

我发现一个npm模块可以用作python的javascript版本zip

zip- array-与Python的zip函数等效的javascript。将每个数组的值合并在一起。

https://www.npmjs.com/package/zip-array

2.tf.data.zip()在Tensorflow.js中

Tensorflow.js用户的另一个替代选择是:如果您需要zippython中函数来使用Javascript中的tensorflow数据集,则可以tf.data.zip()在Tensorflow.js中使用

tf.data.zip()在Tensorflow.js记录在这里

并非内置于JavaScript本身。一些常见的Javascript框架(例如Prototype)提供了一个实现,或者您可以编写自己的实现。

像@Brandon,我建议下划线拉链功能。但是,它的作用类似于zip_longestundefined根据需要附加值,以返回最长输入长度的内容。

我使用了该mixin方法,以扩展了下划线zipShortest,其功能类似于Python,其作用是zip基于库自身的zip

您可以将以下内容添加到常见的JS代码中,然后将其作为下划线的一部分进行调用:例如_.zipShortest([1,2,3], ['a'])returns [[1, 'a']]

// 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;
}});

您可以通过获取内部数组的索引结果来减少数组的数组并映射新数组。

var array1 = [1, 2, 3],
    array2 = ['a','b','c'],
    array3 = [4, 5, 6],
    array = [array1, array2, array3],
    transposed = array.reduce((r, a) => a.map((v, i) => (r[i] || []).concat(v)), []);

console.log(transposed);

ES2020最短变体:

function * zip(arr1, arr2, i = 0) {
  while(arr1[i]) yield [ arr1[i], arr2[i++] ];
}

[ ...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)))]

Mochikit库提供本产品和许多其他Python相似的功能。Mochikit的开发者也是Python爱好者,因此具有Python的通用样式,并且还将异步调用包装在类似扭曲的框架中。

我在纯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;
}

它不是防弹的,但仍然很有趣。

这使Ddi的基于迭代器的答案了一行

function* zip(...toZip) {
  const iterators = toZip.map((arg) => arg[Symbol.iterator]());
  const next = () => toZip = iterators.map((iter) => iter.next());
  while (next().every((item) => !item.done)) {
    yield toZip.map((item) => item.value);
  }
}

如果您对ES6满意,请执行以下操作:

const zip = (arr,...arrs) =>(
                            arr.map(
                              (v,i) => arrs.reduce((a,arr)=>[...a, arr[i]], [v])))
本文地址:http://javascript.askforanswer.com/xiangdangyupythondeziphanshudejavascript.html
文章标签: ,   ,   ,  
版权声明:本文为原创文章,版权归 javascript 所有,欢迎分享本文,转载请保留出处!

文件下载

老薛主机终身7折优惠码boke112

上一篇:
下一篇:

评论已关闭!