Programing

파이썬 람다 식에 여러 문을 가질 수 있습니까?

crosscheck 2020. 8. 28. 06:52
반응형

파이썬 람다 식에 여러 문을 가질 수 있습니까?


나는 다음을 달성하려는 파이썬 초보자입니다.

목록 목록이 있습니다.

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

파이썬에서 맵으로 이것을 수행하는 방법이 있지만 명명 된 함수를 정의하지 않습니까? (예를 들어, 루비의 익명 블록을 사용하면 쉽습니다)


구체적인 질문부터 일반적인 문제에 이르기까지 여러 가지 답변을 드릴 수 있습니다. 따라서 가장 구체적인 것부터 가장 일반적인 것까지 :

Q. 람다에 여러 문장을 넣을 수 있습니까?

A. 아니요.하지만 실제로 람다를 사용할 필요는 없습니다. def대신 문을 넣을 수 있습니다 . 즉 :

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

map(second_lowest, lst)

Q. 목록을 정렬하여 람다에서 두 번째로 낮은 항목을 가져올 수 있습니까?

A. 네. 으로 알렉스의 대답은 밖으로 poinst, 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]

목록에 문을 넣으면 여러 문을 시뮬레이션 할 수 있습니다.

예 :

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

실제로 여러 문을 가질 수는 없지만 람다를 람다로 전달하여이를 시뮬레이션 할 수 있습니다.

편집 : 시간 여행자가 돌아옵니다! 또한 부울 식의 동작 (단락 규칙과 진실성을 염두에 두어야 함)을 악용하여 작업을 연결할 수 있습니다. 삼항 연산자를 사용하면 더 많은 힘을 얻을 수 있습니다. 다시 말하지만, 여러 개의 문을 가질 수는 없지만 물론 많은 함수 호출을 가질 수 있습니다. 이 예제는 많은 데이터로 임의의 쓰레기를 처리하지만 재미있는 일을 할 수 있음을 보여줍니다. print 문은 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)

여기에서 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]

You can in fact have multiple statements in a lambda expression in python. It is not entirely trivial but in your example, the following works:

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

You have to make sure that each statement does not return anything or if it does wrap it in (.. and False). The result is what is returned by the last evaluation.

Example:

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

A Hacky way to combine multiple statements into a single statement in python is to use the "and" keyword as a short-circuit operator. Then you can use this single statement directly as part of the lambda expression.

This is similar to using "&&" as the short-circuit operator in shell languages such as bash.

Also note: You can always fix a function statement to return a true value by wrapping the function.

Example:

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

On second thought, its probably better to use 'or' instead of 'and' since many functions return '0' or None on success. Then you can get rid of the wrapper function in the above example:

junky = lambda x, y: print('hi') or print('there') or print(x) or print(y)

junky("a", "b")

'and' operate will evaluate the expressions until it gets to the first zero return value. after which it short-circuits. 1 and 1 and 0 and 1 evaluates: 1 and 1 and 0, and drops 1

'or' operate will evaluate the expressions until it gets to the first non-zero return value. after which it short-circuits.

0 or 0 or 1 or 0 evaluates 0 or 0 or 1, and drops 0


Or if you want to avoid lambda and have a generator instead of a list:

(sorted(col)[1] for col in lst)


You can do it in O(n) time using min and index instead of using sort or heapq.

First create new list of everything except the min value of the original list:

new_list = lst[:lst.index(min(lst))] + lst[lst.index(min(lst))+1:]

Then take the min value of the new list:

second_smallest = min(new_list)

Now all together in a single lambda:

map(lambda x: min(x[:x.index(min(x))] + x[x.index(min(x))+1:]), lst)

Yes it is really ugly, but it should be algorithmically cheap. Also since some folks in this thread want to see list comprehensions:

[min(x[:x.index(min(x))] + x[x.index(min(x))+1:]) for x in lst]

This is exactly what the bind function in a Monad is used for.

With the bind function you can combine multiple lambda's into one lambda, each lambda representing a statement.


I'll give you another solution, Make your lambda invoke a function.

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

Let me present to you a glorious but terrifying hack:

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)

You can now use this LET form as such:

map(lambda x: LET(('_', x.sort()),
                  lambda _: x[1]),
    lst)

which gives: [345, 465, 333]


There actually is a way you can use multiple statements in lambda. Here's my solution:

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

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

map(x, lst)

Yes. You can define it this way and then wrap your multiple expressions with the following:

Scheme begin:

begin = lambda *x: x[-1]

Common Lisp progn:

progn = lambda *x: x[-1]


There are better solutions without using lambda function. But if we really want to use lambda function, here is a generic solution to deal with multiple statements: map(lambda x: x[1] if (x.sort()) else x[1],lst)

You don't really care what the statement returns.

참고URL : https://stackoverflow.com/questions/862412/is-it-possible-to-have-multiple-statements-in-a-python-lambda-expression

반응형