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 配列の理解またはジェネレーターを使用できるようになります。)