Pythonのzip関数に相当するJavascript 質問する

Pythonのzip関数に相当するJavascript 質問する

Python の zip 関数に相当する JavaScript はありますか? つまり、同じ長さの複数の配列を指定して、ペアの配列を作成します。

たとえば、次のような 3 つの配列があるとします。

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]]

ベストアンサー1

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

(...現時点では、そして将来的にも、この構文にはパフォーマンス上の問題がある可能性があるので注意してください。そのため、2 番目の回答を可変長引数とともに使用する場合は、パフォーマンス テストを行うことをお勧めします。とはいえ、これが標準になってからかなり時間が経っています。)

これを文字列で使用する場合は、必ず補足事項に注意してください (おそらく、es6 iterables では、これを実行するより良い方法があるでしょう)。


ここにワンライナーがあります:

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 バージョンとは異なり、単一のリスト引数を渡すことを前提としています。これらすべての「機能」が必要な場合は、以下を参照してください。必要なコードは 2 行程度です。

以下は、zip配列のサイズが等しくないエッジケースでの Python の動作を模倣し、配列の長い部分が存在しないかのように暗黙的に動作します。

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

これらの最後の 2 つのバージョン (可変長バージョン、つまり複数引数バージョン) を使用する場合、zip はもはやそれ自身の逆関数ではありません。Pythonzip(*[...])の慣用句を模倣するには、zip 関数を反転する場合、または同様に可変数のリストを入力として取得する場合に、次の操作を行う必要がありzip.apply(this, [...])ます。


補遺:

zipこれを任意の反復可能オブジェクト (たとえば、Python では文字列、範囲、マップ オブジェクトなどで使用可能) に処理するには、次のように定義します。

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]]

(または、すでに Python スタイルの関数を記述している場合は、それを使用することもできますrange(...)。最終的には、ECMAScript 配列の理解またはジェネレーターを使用できるようになります。)

おすすめ記事