Update 2016:
Hier ist eine schickere Ecmascript 6-Version:
zip= rows=>rows[0].map((_,c)=>rows.map(row=>row[c]))
Abbildung äquiv. zu Python { zip(*args)
}:
> zip([['row0col0', 'row0col1', 'row0col2'],
['row1col0', 'row1col1', 'row1col2']]);
[["row0col0","row1col0"],
["row0col1","row1col1"],
["row0col2","row1col2"]]
(und FizzyTea weist darauf hin , dass ES6 variadische Argument Syntax hat, so dass die folgende Funktionsdefinition wie Python handeln, aber unter Disclaimer siehe ... das wird nicht über eine eigene inverse sein , so zip(zip(x))
wird nicht gleich x
, obwohl wie Matt Kramer weist darauf hin zip(...zip(...x))==x
(wie in regulärer Python zip(*zip(*x))==x
))
Alternative Definition äquiv. zu 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
(Beachten Sie, dass die ...
Syntax zu diesem Zeitpunkt und möglicherweise in Zukunft möglicherweise Leistungsprobleme aufweist. Wenn Sie also die zweite Antwort mit verschiedenen Argumenten verwenden, möchten Sie sie möglicherweise perfekt testen.)
Hier ist ein Oneliner:
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(...)
Das Obige setzt voraus, dass die Arrays gleich groß sind, wie sie sein sollten. Es wird auch davon ausgegangen, dass Sie ein einzelnes Listenargument übergeben, im Gegensatz zu Pythons Version, bei der die Argumentliste variadisch ist. Wenn Sie alle diese "Funktionen" möchten , siehe unten. Es dauert nur etwa 2 zusätzliche Codezeilen.
Im Folgenden wird das zip
Verhalten von Python in Randfällen nachgeahmt, in denen die Arrays nicht gleich groß sind, und es wird stillschweigend so getan, als ob die längeren Teile der Arrays nicht vorhanden wären:
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()
// []
Dies ahmt das itertools.zip_longest
Verhalten von Python nach und fügt ein, undefined
wo Arrays nicht definiert sind:
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()
// []
Wenn Sie diese beiden letzten Versionen verwenden (verschiedene Versionen mit mehreren Argumenten), ist zip nicht mehr die eigene Umkehrung. Um das zip(*[...])
Idiom von Python nachzuahmen , müssen Sie dies tun, zip.apply(this, [...])
wenn Sie die Zip-Funktion invertieren möchten oder wenn Sie auf ähnliche Weise eine variable Anzahl von Listen als Eingabe haben möchten.
Nachtrag :
Um dieses Handle iterierbar zu machen (z. B. in Python, das Sie zip
für Zeichenfolgen, Bereiche, Kartenobjekte usw. verwenden können), können Sie Folgendes definieren:
function iterView(iterable) {
// returns an array equivalent to the iterable
}
Allerdings , wenn Sie schreiben zip
in der folgenden Art und Weise , auch das wird nicht nötig sein:
function zip(arrays) {
return Array.apply(null,Array(arrays[0].length)).map(function(_,i){
return arrays.map(function(array){return array[i]})
});
}
Demo:
> JSON.stringify( zip(['abcde',[1,2,3,4,5]]) )
[["a",1],["b",2],["c",3],["d",4],["e",5]]
(Oder Sie können eine range(...)
Funktion im Python-Stil verwenden, wenn Sie bereits eine geschrieben haben. Schließlich können Sie ECMAScript-Array-Verständnis oder -Generatoren verwenden.)