tutorial matplot datacamp python haskell

matplot - python 2.7 plot



zip ¿Con analógico en Python? (6)

¿Cuál es el análogo de la función zipWith de Haskell en Python?

zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]


En general, como otros han mencionado, el mapa y el zip pueden ayudarlo a replicar la funcionalidad de zipWith como en Haskel.

En general, puede aplicar un operador binario definido o alguna función binaria en dos listas. Un ejemplo para reemplazar un zip de Haskel con el mapa / zip de Python

Input: zipWith (+) [1,2,3] [3,2,1] Output: [4,4,4] >>> map(operator.add,[1,2,3],[4,3,2]) [5, 5, 5] >>> [operator.add(x,y) for x,y in zip([1,2,3],[4,3,2])] [5, 5, 5] >>>

Hay otras variaciones de zipWith aka zipWith3, zipWith4 .... zipWith7. Para replicar estos funcionalistas es posible que desee utilizar izip y imap en lugar de zip y mapa.

>>> [x for x in itertools.imap(lambda x,y,z:x**2+y**2-z**2,[1,2,3,4],[5,6,7,8],[9,10,11,12])] >>> [x**2+y**2-z**2 for x,y,z in itertools.izip([1,2,3,4],[5,6,7,8],[9,10,11,12])] [-55, -60, -63, -64]

Como puede ver, puede operar con cualquier cantidad de listas que desee y aún puede usar el mismo procedimiento.


Puedes crear el tuyo, si lo deseas, pero en Python lo hacemos principalmente

list_c = [ f(a,b) for (a,b) in zip(list_a,list_b) ]

ya que Python no es intrínsecamente funcional. Simplemente sucede que admite algunos modismos de conveniencia.


Puedes usar el mapa:

>>> x = [1,2,3,4] >>> y = [4,3,2,1] >>> map(lambda a, b: a**b, x, y) [1, 8, 9, 4]


Sé que esta es una vieja pregunta, pero ...

Ya se ha dicho que la forma típica de python sería algo así como

results = [f(a, b) for a, b in zip(list1, list2)]

Entonces, al ver una línea así en tu código, la mayoría de los pitonistas lo entenderán bien.

También ha habido un ejemplo (creo) puramente perezoso que se muestra:

import itertools def zipWith(f, *args): return itertools.starmap(f, itertools.izip(*args))

pero creo que starmap devuelve un iterador, por lo que no podrá indexar, o ir varias veces a lo que devolverá esa función.

Si no está particularmente interesado en la pereza y / o necesita indexar o recorrer repetidas veces su nueva lista, este es probablemente el objetivo más general que podría obtener:

def zipWith(func, *lists): return [func(*args) for args in zip(*lists)]

No es que no puedas hacerlo con la versión perezosa, pero también podrías llamar a esa función como si ya hubieras creado tu lista de listas.

results = zipWith(func, *lists)

o simplemente como normal, como:

results = zipWith(func, list1, list2)

De alguna manera, esa llamada a la función simplemente parece más simple y más fácil de asimilar que la versión de la lista de comprensión.

Al mirar eso, esto parece extrañamente reminiscente de otra función auxiliar que suelo escribir:

def transpose(matrix): return zip(*matrix)

que luego podría escribirse como:

def transpose(matrix): return zipWith(lambda *x: x, *matrix)

No es realmente una versión mejor, pero siempre me resulta interesante cómo cuando escribo funciones genéricas en un estilo funcional, a menudo me encuentro yendo, "Oh. Esa es solo una forma más general de una función que ya he escrito antes".


Un zipWith flojo con itertools:

import itertools def zip_with(f, *coll): return itertools.starmap(f, itertools.izip(*coll))

Esta versión generaliza el comportamiento de zipWith con cualquier número de iterables.


map()

map(operator.add, [1, 2, 3], [3, 2, 1])

Aunque generalmente se usa un LC con zip() .

[x + y for (x, y) in zip([1, 2, 3], [3, 2, 1])]