Tengo una función que devuelve dos valores y me gustaría usar una lista de comprensión para llenar dos listas. por ejemplo:
def f(x): return 2*x,x*x x = range(3) xlist, ylist = [f(value) for value in x] EDITS from answers below: xtuple, ytuple = zip(*[f(value) for value in x]) xlist, ylist = map(list,zip(*[f(value) for value in x]))donde el rendimiento esperado debe ser:
xlist = [0, 2, 4] ylist = [0, 1, 4]mi pregunta se reduce a:
Actualmente obtengo una lista de tuplas, aunque esto es razonable, terminaré necesitando dos listas independientes. actualmente podría tener 1 variable de marcador de posición (lista de tuplas) y 3 comprensiones totales. Pero me pregunto si hay una forma limpia de hacerlo con una comprensión de lista única.
Vale la pena señalar: en el código real, mis dos retornos están correlacionados, por lo que no puedo simplemente dividir la función en dos.
En primer lugar, cometiste un pequeño error: debería ser:
[f(value) for value in x] # ^ notice the `value`en vez de:
[f(x) for value in x]Además, el punto es que:
return 2*x,xes la abreviatura de:
return (2*x,x) pues una tupla . Su comprensión de lista genera una lista de tuplas , no una tupla de listas. Sin embargo, lo bueno de zip es que puedes usarlo fácilmente al revés con el asterisco:
xlist,ylist = zip(* [f(value) for value in x] ) # ^ with asterisk Tenga en cuenta que xlist y ylist serán tuplas (ya que zip se desempaquetará). Si desea que sean listas, puede, por ejemplo, utilizar:
xlist,ylist = map(list, zip(*[f(value) for value in x]) )lo que resulta en:
>>> xlist [0, 2, 4] >>> ylist [0, 1, 4] (tenga en cuenta que los range comienzan a contar desde 0)
Alternativa : otra forma de hacer esto es, por supuesto:
xlist = [f(value)[0] for value in x] ylist = [f(value)[1] for value in x] Pero, por supuesto, esto es poco elegante y, además, puede ser ineficiente (dado que f es computacionalmente costoso).
Hagamos que esto funcione. La función está bien:
def f(x): return 2*x, x*xPero desea definir el rango de la siguiente manera, observe los valores inicial y final:
x = range(1, 4) Además, debe llamar a la función con el valor , no con la lista como parámetro. Y el último truco para descomprimir el resultado en dos listas es simplemente zip(*lst) el resultado de la comprensión de la lista:
xlist, ylist = zip(*[f(value) for value in x])Ahora el resultado es el esperado:
xlist => [2, 4, 6] ylist => [1, 4, 9]