list comprehension - convertir - enumerar y zip dentro de Coffeescript?
js to coff (6)
Viniendo de Python, me gustan muchas de las características que Coffeescript toma de Python y Perl (rangos / divisiones, comprensiones, asignaciones de desestructuración). ¿Hay algún azúcar sintáctico en Coffeescript para imitar las funciones enumerate
o zip
( itertools.izip
) de itertools.izip
?
Estos son los patrones que no me importan mucho:
# an enumerate call would be helpful here
i = 0
for x in arr
... use x and i ...
i++
y
# a zip would be useful here
n = Math.min(arr1.length,arr2.length)
for i in 0...n
x = arr1[i]; y = arr2[i]
... use x and y ...
Enumerar:
arr.forEach (x, i) ->
... use x and i ...
zip
/ zipWith
(aprendí esto de Haskell, supongo que significan lo mismo en Python):
zip = (arr1, arr2) ->
basic_zip = (el1, el2) -> [el1, el2]
zipWith basic_zip, arr1, arr2
zipWith = (func, arr1, arr2) ->
min = Math.min arr1.length, arr2.length
ret = []
for i in [0...min]
ret.push func(arr1[i], arr2[i])
ret
Algunos ejemplos (probados):
zip([1, 2, 3], [4, 5, 6]) # => [[1, 4], [2, 5], [3, 6]]
add = (el1, el2) -> el1 + el2
zipWith(add, [1, 2, 3], [4, 5, 6]) # => [5, 7, 9]
Actualización : al estilo Haskell reimplementado, solo por diversión. No es tan genial sin la coincidencia de patrones, pero bueno ...
zipWith = (func, arr1, arr2) ->
return [] if arr1.length is 0 or arr2.length is 0
el1 = arr1.shift()
el2 = arr2.shift()
ret_arr = zipWith func, arr1, arr2
ret_arr.unshift func(el1, el2)
ret_arr
Oh, amigo, esto fue divertido. SO necesita más preguntas como esta: D
No olvide que CoffeeScript es solo una sintaxis alternativa para ECMAScript. Al menos para su primer ejemplo, hay una función ECMAscript perfectamente perfecta ( Array.prototype.forEach
), que ya hace lo que desea:
arr = ["a", "b", "c"]
arr.forEach (el, i) ->
alert "Element #{el} is at index #{i}"
Desafortunadamente, no hay Array.prototype.zip
o Array.prototype.zipWith
. Esa parece ser una omisión bastante grande, especialmente considerando que hay tanto reduce
como reduceRight
, el último de los cuales muchos otros idiomas no tienen. Supongo que es un simple descuido, y vamos a ver zip
en alguna versión futura del lenguaje.
Para comprimir y otras funciones de utilidad, Underscore.js es más o menos la biblioteca estándar, y resulta que ha sido creada por Jeremy Ashkenas, el hombre detrás de CoffeeScript. Con él, puedes escribir tu zip como ejemplo
for elems in _.zip(arr1, arr2)
x = elems[0]; y = elems[1]
...
o mejor aún
for [x, y] in _.zip(arr1, arr2)
...
usando patrón de coincidencia. Sin embargo, _.zip
que _.zip
usa la longitud máxima de arr1
y arr2
, no el mínimo; por lo tanto, si no desea manejar valores undefined
, primero debe truncar la matriz más larga.
También hay una implementación CoffeeScript de Underscore, Underscore.coffee , que es un gran lugar para mirar si se está preguntando cómo implementar un bucle particular en CoffeeScript.
Para zip, prueba este:
zip = (x...) ->
(y[i] for y in x for i in [0...Math.min (y.length for y in x)...])
Si prefieres comprimir hasta el final, usa Math.max()
.
forEach está construido de manera efectiva en:
a = [''a'',''b'',''c'']
for el,i in a
alert "Element #{el} is at index #{i}"
El Cookbook CoffeeScript enumera una buena implementación de una función zip:
# Usage: zip(arr1, arr2, arr3, ...)
zip = () ->
lengthArray = (arr.length for arr in arguments)
length = Math.min(lengthArray...)
for i in [0...length]
arr[i] for arr in arguments
zip([0, 1, 2, 3], [0, -1, -2, -3])
# => [[0, 0], [1, -1], [2, -2], [3, -3]]
http://coffeescriptcookbook.com/chapters/arrays/zip-function