python - ejemplos - django
¿Es posible tener múltiples declaraciones en una expresión python lambda? (14)
Aquí puedo dar varias respuestas diferentes, desde su pregunta específica a preocupaciones más generales. así que de lo más específico a lo más general:
P. ¿Puedes poner múltiples enunciados en un lambda?
R. No. Pero en realidad no necesitas usar una lambda. Puede poner las declaraciones en una def
lugar. es decir:
def second_lowest(l):
l.sort()
return l[1]
map(second_lowest, lst)
P. ¿Puede obtener el segundo artículo más bajo de una lambda clasificando la lista?
A. Sí. Como señala la respuesta de Alex, sorted()
es una versión del género que crea una nueva lista, en lugar de ordenarla en el lugar, y puede encadenarse. Tenga en cuenta que esto es probablemente lo que debería estar usando; es una mala práctica que su mapa tenga efectos secundarios en la lista original.
P. ¿Cómo debo obtener el segundo artículo más bajo de cada lista en una secuencia de listas?
A. sorted(l)[1]
no es realmente la mejor manera para esto. Tiene complejidad O (N log (N)), mientras que existe una solución O (n). Esto se puede encontrar en el módulo heapq.
>>> import heapq
>>> l = [5,2,6,8,3,5]
>>> heapq.nsmallest(l, 2)
[2, 3]
Entonces solo usa:
map(lambda x: heapq.nsmallest(x,2)[1], list_of_lists)
También se considera más claro utilizar una lista de comprensión, lo que evita la lambda por completo:
[heapq.nsmallest(x,2)[1] for x in list_of_lists]
Soy un principiante de Python tratando de lograr lo siguiente:
Tengo una lista de listas:
lst = [[567,345,234],[253,465,756, 2345],[333,777,111, 555]]
Quiero un mapa primero en otra lista que contenga solo el segundo número más pequeño de cada sublista. Entonces el resultado debería ser:
[345, 465, 333]
Por ejemplo, si solo estuviera interesado en el número más pequeño, podría:
map(lambda x: min(x),lst)
Ojalá pudiera hacer esto:
map(lambda x: sort(x)[1],lst)
pero el género no encadena. (regresa Ninguno)
tampoco se permite algo como esto:
map(lambda x: sort(x); x[1],lst) #hence the multiple statement question
¿Hay alguna manera de hacer esto con map en python pero sin definir una función nombrada ? (es fácil con bloques anónimos en ruby, por ejemplo)
Déjame presentarte un truco glorioso pero aterrador:
import types
def _obj():
return lambda: None
def LET(bindings, body, env=None):
''''''Introduce local bindings.
ex: LET((''a'', 1,
''b'', 2),
lambda o: [o.a, o.b])
gives: [1, 2]
Bindings down the chain can depend on
the ones above them through a lambda.
ex: LET((''a'', 1,
''b'', lambda o: o.a + 1),
lambda o: o.b)
gives: 2
''''''
if len(bindings) == 0:
return body(env)
env = env or _obj()
k, v = bindings[:2]
if isinstance(v, types.FunctionType):
v = v(env)
setattr(env, k, v)
return LET(bindings[2:], body, env)
Ahora puede usar este formulario LET
como tal:
map(lambda x: LET((''_'', x.sort()),
lambda _: x[1]),
lst)
que da: [345, 465, 333]
De hecho, hay una forma de que puedas usar múltiples declaraciones en lambda. Aquí está mi solución:
lst = [[567,345,234],[253,465,756, 2345],[333,777,111, 555]]
x = lambda l: exec("l.sort(); return l[1]")
map(x, lst)
De hecho, puede tener varias instrucciones en una expresión lambda en python. No es del todo trivial, pero en su ejemplo, los siguientes trabajos:
map(lambda x: x.sort() or x[1],lst)
Debe asegurarse de que cada instrucción no devuelva nada o de que se ajuste (... y False). El resultado es lo que devuelve la última evaluación.
Ejemplo:
>>> f = (lambda : (print(1) and False) or (print(2) and False) or (print(3) and False))
>>> f()
1
2
3
Esto es exactamente para lo que se usa la función de bind
en una Monad .
Con la función de vinculación puede combinar múltiples lambda en una lambda, cada lambda representa una declaración.
O si desea evitar lambda y tener un generador en lugar de una lista:
(ordenado (col) [1] para col en lst)
Poner las declaraciones en una lista puede simular varias declaraciones:
P.ej:
lambda x: [f1(x), f2(x), f3(x), x+1]
Puedes hacerlo en tiempo O (n) usando min e index en lugar de usar sort o heapq.
Primero crea una nueva lista de todo excepto el valor mínimo de la lista original:
new_list = lst[:lst.index(min(lst))] + lst[lst.index(min(lst))+1:]
Luego tome el valor mínimo de la nueva lista:
second_smallest = min(new_list)
Ahora todos juntos en una sola lambda:
map(lambda x: min(x[:x.index(min(x))] + x[x.index(min(x))+1:]), lst)
Sí, es realmente feo, pero debería ser algorítmicamente barato. Además, dado que algunas personas en este hilo quieren ver listas de comprensión:
[min(x[:x.index(min(x))] + x[x.index(min(x))+1:]) for x in lst]
Sí. Puede definirlo de esta manera y luego ajustar sus expresiones múltiples con lo siguiente:
El esquema comienza:
begin = lambda * x: x [-1]
Common Lisp progn:
progn = lambda * x: x [-1]
Te daré otra solución, haz que tu lambda invoque una función.
def multiple_statements(x, y):
print(''hi'')
print(''there'')
print(x)
print(y)
return 1
junky = lambda x, y: multiple_statements(x, y)
junky(''a'', ''b'');
Una forma de Hacky de combinar declaraciones múltiples en una sola declaración en python es usar la palabra clave "y" como operador de cortocircuito. Entonces puede usar esta declaración individual directamente como parte de la expresión lambda.
Esto es similar a usar "&&" como operador de cortocircuito en lenguajes de shell como bash.
También tenga en cuenta: siempre puede corregir una declaración de función para devolver un valor verdadero al envolver la función.
Ejemplo:
def p2(*args):
print(*args)
return 1 # a true value
junky = lambda x, y: p2(''hi'') and p2(''there'') and p2(x) and p2(y)
junky("a", "b")
Pensándolo bien, probablemente sea mejor usar ''o'' en lugar de ''y'' ya que muchas funciones devuelven ''0'' o None en caso de éxito. Entonces puede deshacerse de la función de envoltura en el ejemplo anterior:
junky = lambda x, y: print(''hi'') or print(''there'') or print(x) or print(y)
junky("a", "b")
''y'' operar evaluará las expresiones hasta que llegue al primer valor de retorno cero. después de lo cual se cortocircuita. 1 y 1 y 0 y 1 evalúa: 1 y 1 y 0, y cae 1
''o'' operar evaluará las expresiones hasta que llegue al primer valor de retorno distinto de cero. después de lo cual se cortocircuita.
0 o 0 o 1 o 0 evalúa 0 o 0 o 1, y cae 0
Usando begin () desde aquí: http://www.reddit.com/r/Python/comments/hms4z/ask_pyreddit_if_you_were_making_your_own/c1wycci
Python 3.2 (r32:88445, Mar 25 2011, 19:28:28)
[GCC 4.5.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> lst = [[567,345,234],[253,465,756, 2345],[333,777,111, 555]]
>>> begin = lambda *args: args[-1]
>>> list(map(lambda x: begin(x.sort(), x[1]), lst))
[345, 465, 333]
Use la función ordenada , como esta:
map(lambda x: sorted(x)[1],lst)
Viajero del tiempo aquí. Si generalmente quiere tener múltiples declaraciones dentro de una lambda, puede pasar otras lambdas como argumentos a esa lambda.
(lambda x, f: list((y[1] for y in f(x))))(lst, lambda x: (sorted(y) for y in x))
En realidad, no puedes tener varias declaraciones, pero puedes simular eso pasando lambdas a lambdas.
Editar: ¡ el viajero del tiempo vuelve! También puede abusar del comportamiento de las expresiones booleanas (teniendo en cuenta las reglas de cortocircuito y la veracidad) para las operaciones de cadena. Usar el operador ternario te da aún más poder. Nuevamente, no puede tener múltiples declaraciones , pero puede tener muchas llamadas a funciones. Este ejemplo hace un poco de basura arbitraria con un montón de datos, pero muestra que puedes hacer algunas cosas divertidas. Las instrucciones de impresión son ejemplos de funciones que devuelven None
(al igual que el método .sort()
) pero también ayudan a mostrar lo que está haciendo la lambda
.
>>> (lambda x: print(x) or x+1)(10)
10
11
>>> f = (lambda x: x[::2] if print(x) or x.sort() else print(enumerate(x[::-1]) if print(x) else filter(lambda (i, y): print((i, y)) or (i % 3 and y % 2), enumerate(x[::-1]))))
>>> from random import shuffle
>>> l = list(range(100))
>>> shuffle(l)
>>> f(l)
[84, 58, 7, 99, 17, 14, 60, 35, 12, 56, 26, 48, 55, 40, 28, 52, 31, 39, 43, 96, 64, 63, 54, 37, 79, 25, 46, 72, 10, 59, 24, 68, 23, 13, 34, 41, 94, 29, 62, 2, 50, 32, 11, 97, 98, 3, 70, 93, 1, 36, 87, 47, 20, 73, 45, 0, 65, 57, 6, 76, 16, 85, 95, 61, 4, 77, 21, 81, 82, 30, 53, 51, 42, 67, 74, 8, 15, 83, 5, 9, 78, 66, 44, 27, 19, 91, 90, 18, 49, 86, 22, 75, 71, 88, 92, 33, 89, 69, 80, 38]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99]
(0, 99)
(1, 98)
(2, 97)
(3, 96)
(4, 95)
(5, 94)
(6, 93)
(7, 92)
(8, 91)
(9, 90)
(10, 89)
(11, 88)
(12, 87)
(13, 86)
(14, 85)
(15, 84)
(16, 83)
(17, 82)
(18, 81)
(19, 80)
(20, 79)
(21, 78)
(22, 77)
(23, 76)
(24, 75)
(25, 74)
(26, 73)
(27, 72)
(28, 71)
(29, 70)
(30, 69)
(31, 68)
(32, 67)
(33, 66)
(34, 65)
(35, 64)
(36, 63)
(37, 62)
(38, 61)
(39, 60)
(40, 59)
(41, 58)
(42, 57)
(43, 56)
(44, 55)
(45, 54)
(46, 53)
(47, 52)
(48, 51)
(49, 50)
(50, 49)
(51, 48)
(52, 47)
(53, 46)
(54, 45)
(55, 44)
(56, 43)
(57, 42)
(58, 41)
(59, 40)
(60, 39)
(61, 38)
(62, 37)
(63, 36)
(64, 35)
(65, 34)
(66, 33)
(67, 32)
(68, 31)
(69, 30)
(70, 29)
(71, 28)
(72, 27)
(73, 26)
(74, 25)
(75, 24)
(76, 23)
(77, 22)
(78, 21)
(79, 20)
(80, 19)
(81, 18)
(82, 17)
(83, 16)
(84, 15)
(85, 14)
(86, 13)
(87, 12)
(88, 11)
(89, 10)
(90, 9)
(91, 8)
(92, 7)
(93, 6)
(94, 5)
(95, 4)
(96, 3)
(97, 2)
(98, 1)
(99, 0)
[(2, 97), (4, 95), (8, 91), (10, 89), (14, 85), (16, 83), (20, 79), (22, 77), (26, 73), (28, 71), (32, 67), (34, 65), (38, 61), (40, 59), (44, 55), (46, 53), (50, 49), (52, 47), (56, 43), (58, 41), (62, 37), (64, 35), (68, 31), (70, 29), (74, 25), (76, 23), (80, 19), (82, 17), (86, 13), (88, 11), (92, 7), (94, 5), (98, 1)]