Оновлення 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(...)
Вищесказане передбачає, що масиви мають однаковий розмір, як і повинні бути. Він також передбачає, що ви передаєте один аргумент списку списків, на відміну від версії Python, де список аргументів є варіативним. Якщо ви хочете всі ці "функції", дивіться нижче. Це займає близько двох додаткових рядків коду.
Далі буде імітувати 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 aka. Версія з кількома аргументами), 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 або генератори.)