2016 actualización:
Aquí hay una versión snazzier EcmaScript 6:
zip= rows=>rows[0].map((_,c)=>rows.map(row=>row[c]))
Ilustración:
> zip([['row0col0', 'row0col1', 'row0col2'],
['row1col0', 'row1col1', 'row1col2']]);
[["row0col0","row1col0"],
["row0col1","row1col1"],
["row0col2","row1col2"]]
(y FizzyTea señala que ES6 tiene una sintaxis argumento variadic, por lo que la siguiente actuará como Python, pero vea a continuación la exención de responsabilidad ... esto no será su propio inverso así que zip(zip(x))
no será igual x
:)
> 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
(Ten en cuenta que la sintaxis ...
puede tener problemas de rendimiento en este momento, y posiblemente en el futuro, por lo que si se utiliza la segunda respuesta con argumentos variadic, es posible que desee prueba perf.)
Aquí hay una 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(...)
Lo anterior supone que las matrices son de igual tamaño, como debe ser. También asume que pasa en una sola lista de argumentos de listas, a diferencia de la versión de Python, donde la lista de argumentos es variadica. Si desea todas estas "características", consulte a continuación. Solo toma unas 2 líneas adicionales de código.
A continuación se imitan el comportamiento de Python zip
en casos extremos, donde las matrices no son de igual tamaño, en silencio simulando las partes más largas de las matrices no existen:
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()
// []
Esto imitar el comportamiento de Python itertools.zip_longest
, insertando undefined
, donde las matrices no están definidos:
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 utiliza estos dos última versión (. variadic aka-versiones de argumento múltiple), entonces zip ya no es su propio inverso. Para imitar la expresión zip(*[...])
de Python, deberá hacer zip.apply(this, [...])
cuando desee invertir la función zip o si desea tener una cantidad variable de listas como entrada.
adición:
Para que esto sea manejar cualquier iterable (por ejemplo en Python puede utilizar zip
en cadenas, oscila, los objetos de mapa, etc.), se podría definir lo siguiente:
function iterView(iterable) {
// returns an array equivalent to the iterable
}
sin embargo, si usted escribe zip
en el siguiente way, incluso eso no será necesario:
function zip(arrays) {
return Array.apply(null,Array(arrays[0].length)).map(function(_,i){
return arrays.map(function(array){return array[i]})
});
}
Demostración:
> JSON.stringify(zip(['abcde',[1,2,3,4,5]]))
[["a",1],["b",2],["c",3],["d",4],["e",5]]
(O usted podría utilizar una función range(...)
de estilo de Python si has uno ya escrito. Eventualmente podrá usar compilaciones o generadores ECMAScript.)
Es justo decir que los programadores de Python estamos "temerosos" de los métodos tontos que implican bucles porque son lentos, y por lo tanto, siempre buscamos métodos integrados para hacer las cosas. Pero eso en Javascript deberíamos continuar y escribir nuestros loops porque no son particularmente lentos. – LondonRob
@LondonRob Un bucle es un bucle, oculto detrás de un método "rápido" o no. JavaScript definitivamente ha estado recibiendo más soporte para las funciones de orden superior, con la introducción de Array 'forEach',' reduce', 'map',' every', etc. Simplemente fue el caso de que 'zip' no" hiciera cut "(también está ausente un 'flatMap'), no por consideraciones de rendimiento, pero para ser justos, .NET (3.5) no tenía un Zip en Enumerable por un par de años. Cualquier biblioteca 'funcional' como guión bajo/lodash (lodash 3.x tiene evaluación de secuencia diferida) proporcionará una función zip equivalente. – user2864740
@ user2864740 Un bucle interpretado (como en Python) siempre será * mucho * más lento que un bucle de código de máquina. Un bucle compilado JIT (como en los motores JS modernos) puede acercarse a la velocidad de CPU nativa, tanto que la ganancia introducida mediante el uso de un bucle de código de máquina puede compensarse con la sobrecarga de la llamada de función anónima. Aún así, tiene sentido tener estas funciones integradas y perfilar varias variaciones de sus "bucles internos" con varios motores JS. Los resultados pueden no ser obvios. – Tobia