Обновление 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
; хотя, как указывает Мэтт Крамер zip(...zip(...x))==x
(например, в штатном питоне 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(...)
Выше предполагается, что массивы имеют одинаковый размер, как и должно быть. Также предполагается, что вы передаете один аргумент list списков, в отличие от версии 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()
// []
Это будет имитировать itertools.zip_longest
поведение Python , вставляя 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, то есть версии с несколькими аргументами), то 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.)