Возможно ли иметь несколько операторов в лямбда-выражении python?
Я новичок python, пытающийся достичь следующего:
у меня есть список списков:
lst = [[567,345,234],[253,465,756, 2345],[333,777,111, 555]]
Я хочу map lst в другой список, содержащий только второе наименьшее число из каждого подсписка. Так что результат должен быть:
[345, 465, 333]
например, если бы меня просто интересовало наименьшее число, я мог бы сделать:
map(lambda x: min(x),lst)
Я хотел бы сделать это:
map(lambda x: sort(x)[1],lst)
но вроде не цепь. (возвращает None)
ни это что-то вроде этого разрешено:
map(lambda x: sort(x); x[1],lst) #hence the multiple statement question
есть ли способ сделать это с map в Python, но без определения имени функции? (это легко с анонимными блоками в Ruby, например)
14 ответов:
есть несколько различных ответов, которые я могу дать здесь, от вашего конкретного вопроса до более общих проблем. Итак, от самого конкретного к самому общему:
вопрос: можете ли вы поместить несколько операторов в лямбда?
А. нет. Но на самом деле вам не нужно использовать лямбда. Вы можете поместить заявления в . т. е.:
def second_lowest(l): l.sort() return l[1] map(second_lowest, lst)
вопрос: можете ли вы получить второй самый низкий элемент из лямбды, отсортировав список?
А. да. Как Алекс poinst out,
sorted()
это версия сортировки, которая создает новый список, а не сортировка на месте, и может быть прикован. Обратите внимание, что это, вероятно, то, что вы должны использовать - это плохая практика для вашей карты, чтобы иметь побочные эффекты в исходном списке.вопрос: как я должен получить второй самый низкий элемент из каждого списка в последовательности списков.
А.
sorted(l)[1]
is на самом деле не лучший способ для этого. Он имеет сложность O(N log(N)), в то время как решение O (n) существует. Это можно найти в модуле heapq.>>> import heapq >>> l = [5,2,6,8,3,5] >>> heapq.nsmallest(l, 2) [2, 3]
так что просто используйте:
map(lambda x: heapq.nsmallest(x,2)[1], list_of_lists)
также обычно считается более ясным использовать понимание списка, которое полностью избегает лямбды:
[heapq.nsmallest(x,2)[1] for x in list_of_lists]
размещение операторов в списке может имитировать несколько операторов:
например:
lambda x: [f1(x), f2(x), f3(x), x+1]
путешественник во времени здесь. Если вы обычно хотите иметь несколько операторов в лямбде, вы можете передать другие лямбды в качестве аргументов для этой лямбды.
(lambda x, f: list((y[1] for y in f(x))))(lst, lambda x: (sorted(y) for y in x))
на самом деле вы не можете иметь несколько операторов, но вы можете имитировать это, передавая лямбды в лямбды.
Edit: путешественник во времени возвращается! Вы также можете злоупотреблять поведением булевых выражений (имея в виду правила короткого замыкания и правдивость) для цепных операций. С помощью тернарный оператор дает вам еще больше энергии. Опять же, вы не можете иметь несколько заявления, но вы, конечно, можете иметь много вызовов функций. Этот пример делает некоторый произвольный мусор с кучей данных, но он показывает, что вы можете делать некоторые забавные вещи. Операторы печати являются примерами функций, которые возвращают
None
(как и.sort()
способ), но они также помогают показать, что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)]
использовать отсортированный функция, например:
map(lambda x: sorted(x)[1],lst)
или если вы хотите избежать лямбда и иметь генератор вместо списка:
(сортировка (col) [1] для col в lst)
используя begin () отсюда: 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]
вы можете фактически иметь несколько операторов в лямбда-выражении в python. Это не совсем тривиально, но в вашем примере, следующие работы:
map(lambda x: x.sort() or x[1],lst)
вы должны убедиться, что каждый оператор ничего не вернуть или же завернуть его в (.. и ложь). Результат-это то, что возвращается последней оценкой.
пример:
>>> f = (lambda : (print(1) and False) or (print(2) and False) or (print(3) and False)) >>> f() 1 2 3
хакерский способ объединить несколько операторов в один оператор в python заключается в использовании ключевого слова "и" в качестве оператора короткого замыкания. Затем вы можете использовать этот единственный оператор непосредственно как часть лямбда-выражения.
это похоже на использование "&&" в качестве оператора короткого замыкания в языках оболочки, таких как bash.
также Примечание: Вы всегда можете исправить оператор функции, чтобы вернуть истинное значение, обернув функция.
пример:
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")
на второй мысли, его, вероятно, лучше использовать 'или' вместо 'и' так как многие функции возвращают '0' или нет на успех. Тогда вы можете избавиться от функции обертки в приведенном выше примере:
junky = lambda x, y: print('hi') or print('there') or print(x) or print(y) junky("a", "b")
' и ' operate будет оценивать выражения, пока не получит первое нулевое возвращаемое значение. после чего произошло короткое замыкание. 1 и 1 и 0 и 1 оценивает: 1 и 1 и 0, и падает 1
" или " работать будет вычисляйте выражения, пока не будет получено первое ненулевое возвращаемое значение. после чего произошло короткое замыкание.
0 или 0 или 1 или 0 вычисляет 0 или 0 или 1, и отбрасывает 0
Я дам вам другое решение, чтобы ваша лямбда вызывала функцию.
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');
вы можете сделать это в O(n) времени с помощью min и index вместо использования сортировки или heapq.
сначала создайте новый список всего, кроме минимального значения исходного списка:
new_list = lst[:lst.index(min(lst))] + lst[lst.index(min(lst))+1:]
затем возьмите минимальное значение нового списка:
second_smallest = min(new_list)
теперь все вместе в одной лямбде:
map(lambda x: min(x[:x.index(min(x))] + x[x.index(min(x))+1:]), lst)
Да, это действительно некрасиво, но это должно быть алгоритмически дешевые. Также, поскольку некоторые люди в этой теме хотят видеть список понимания:
[min(x[:x.index(min(x))] + x[x.index(min(x))+1:]) for x in lst]
именно так на монады используется для.
С
bind
функция вы можете объединить несколько лямбда в одну лямбда, каждая лямбда представляет собой оператор.
на самом деле есть способ использовать несколько операторов в лямбда. Вот мое решение:
lst = [[567,345,234],[253,465,756, 2345],[333,777,111, 555]] x = lambda l: exec("l.sort(); return l[1]") map(x, lst)
позвольте мне представить вам славный, но страшный Хак:
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)
теперь вы можете использовать этот
LET
в таком виде:map(lambda x: LET(('_', x.sort()), lambda _: x[1]), lst)
что дает:
[345, 465, 333]