Mise à jour 2016:
Voici une version Ecmascript 6 plus brillante:
zip= rows=>rows[0].map((_,c)=>rows.map(row=>row[c]))
Illustration équiv. vers Python { zip(*args)
}:
> zip([['row0col0', 'row0col1', 'row0col2'],
['row1col0', 'row1col1', 'row1col2']]);
[["row0col0","row1col0"],
["row0col1","row1col1"],
["row0col2","row1col2"]]
(et FizzyTea souligne que ES6 a une syntaxe d'argument variadique, donc la définition de fonction suivante agira comme python, mais voir ci-dessous pour l'avertissement ... ce ne sera pas son propre inverse donc zip(zip(x))
ne sera pas égal x
; bien que Matt Kramer le souligne zip(...zip(...x))==x
(comme en python normal zip(*zip(*x))==x
))
Définition alternative équiv. vers 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
(Notez que la ...
syntaxe peut avoir des problèmes de performances à ce stade, et peut-être à l'avenir, donc si vous utilisez la deuxième réponse avec des arguments variadiques, vous voudrez peut-être la tester.)
Voici un 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(...)
Ce qui précède suppose que les tableaux sont de taille égale, comme ils devraient l'être. Il suppose également que vous transmettez un seul argument de liste de listes, contrairement à la version de Python où la liste d'arguments est variadique. Si vous voulez toutes ces "fonctionnalités", voir ci-dessous. Il faut environ 2 lignes de code supplémentaires.
Les éléments suivants imiteront le zip
comportement de Python dans les cas de périphérie où les tableaux ne sont pas de taille égale, en prétendant silencieusement que les parties les plus longues des tableaux n'existent pas:
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()
// []
Cela imitera le itertools.zip_longest
comportement de Python , en insérant undefined
où les tableaux ne sont pas définis:
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()
// []
Si vous utilisez ces deux dernières versions (variadic aka. Versions à arguments multiples), alors zip n'est plus son propre inverse. Pour imiter l' zip(*[...])
idiome de Python, vous devrez le faire zip.apply(this, [...])
lorsque vous souhaitez inverser la fonction zip ou si vous souhaitez également avoir un nombre variable de listes en entrée.
addendum :
Pour que cette poignée soit itérable (par exemple en Python que vous pouvez utiliser zip
sur des chaînes, des plages, des objets de carte, etc.), vous pouvez définir les éléments suivants:
function iterView(iterable) {
// returns an array equivalent to the iterable
}
Cependant, si vous écrivez zip
de la manière suivante , même cela ne sera pas nécessaire:
function zip(arrays) {
return Array.apply(null,Array(arrays[0].length)).map(function(_,i){
return arrays.map(function(array){return array[i]})
});
}
Démo:
> JSON.stringify( zip(['abcde',[1,2,3,4,5]]) )
[["a",1],["b",2],["c",3],["d",4],["e",5]]
(Ou vous pouvez utiliser une range(...)
fonction de style Python si vous en avez déjà écrite une. Finalement, vous pourrez utiliser des générateurs ou des compréhensions de tableaux ECMAScript.)