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])]