Возможно ли иметь несколько операторов в выражении лямбда python?

Я новичок python, пытающийся добиться следующего:

У меня есть список списков:

lst = [[567,345,234],[253,465,756, 2345],[333,777,111, 555]]

Я хочу, чтобы карта 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

Есть ли способ сделать это с помощью карты в python, но без определения именованной функции? (например, с анонимными блоками в рубине)

Ответ 1

Есть несколько разных ответов, которые я могу дать здесь, от вашего конкретного вопроса до более общих проблем. поэтому от наиболее специфических до самых общих:

Q. Можете ли вы поместить несколько операторов в лямбда?

A. Нет. Но на самом деле вам не нужно использовать лямбду. Вы можете поместить операторы в def. то есть:

def second_lowest(l):
    l.sort()
    return l[1]

map(second_lowest, lst)

Q. Можете ли вы получить второй наименьший элемент из лямбда, отсортировав список?

A. Да. Поскольку alex answer poinst out, sorted() - это версия рода, которая создает новый список, а не сортирует на месте и может быть привязана. Обратите внимание, что это, вероятно, то, что вы должны использовать, - плохая практика для вашей карты иметь побочные эффекты в исходном списке.

Q. Как получить второй наименьший элемент из каждого списка в последовательности списков.

A. sorted(l)[1] на самом деле не лучший способ для этого. Он имеет сложность 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]

Ответ 2

Ввод операторов в список может моделировать несколько операторов:

например:.

lambda x: [f1(x), f2(x), f3(x), x+1]

Ответ 3

Путешественник времени здесь. Если вы обычно хотите иметь несколько операторов в лямбда, вы можете передать другие лямбды в качестве аргументов этой лямбда.

(lambda x, f: list((y[1] for y in f(x))))(lst, lambda x: (sorted(y) for y in x))

На самом деле у вас не может быть нескольких операторов, но вы можете имитировать это, передавая lambdas в lambdas.

Изменить: Путешественник во времени возвращается! Вы также можете злоупотреблять поведением булевых выражений (имея в виду правила короткого замыкания и правдивость) для операций цепочки. Использование тернарного оператора дает вам еще большую мощность. Опять же, вы не можете иметь несколько операторов, но, конечно, можете иметь много вызовов функций. В этом примере делается какой-то произвольный хлам с кучей данных, но он показывает, что вы можете делать какие-то забавные вещи. Операторы печати являются примерами функций, возвращающих 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)]

Ответ 5

Или если вы хотите избежать лямбда и иметь генератор вместо списка:

(отсортировано (col) [1] для col в lst)

Ответ 7

Фактически у вас есть несколько операторов в выражении лямбда в python. Это не совсем тривиально, но в вашем примере следующие работы:

map(lambda x: x.sort() or x[1],lst)

Вы должны убедиться, что каждый оператор ничего не возвращает, или если он завершает его (.. и False). Результатом является то, что возвращается последней оценкой.

Пример:

>>> f = (lambda : (print(1) and False) or (print(2) and False) or (print(3) and False))
>>> f()
1
2
3

Ответ 8

Хакский способ объединить несколько операторов в один оператор в 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")

'и' operation будут оценивать выражения до тех пор, пока они не вернутся к первому нулевому возвращаемому значению. после чего он замыкается. 1 и 1 и 0 и 1 оценивает: 1 и 1 и 0 и падает 1

'или' operation будут оценивать выражения до тех пор, пока они не получат первое ненулевое возвращаемое значение. после чего он замыкается.

0 или 0 или 1 или 0 оценивает 0 или 0 или 1 и падает 0

Ответ 9

Вы можете сделать это в O (n), используя min и index вместо использования sort или 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]

Ответ 10

Это именно то, что используется функция bind в Monad.

С помощью функции bind вы можете объединить несколько лямбда в одну лямбда, каждая лямбда, представляющая оператор.

Ответ 11

Я дам вам другое решение. Сделайте свою лямбду вызывающей функцией.

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');

Ответ 12

Позвольте мне представить вам славный, но ужасающий взлом:

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]

Ответ 13

Фактически вы можете использовать несколько операторов в лямбда. Здесь мое решение:

lst = [[567,345,234],[253,465,756, 2345],[333,777,111, 555]]

x = lambda l: exec("l.sort(); return l[1]")

map(x, lst)