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


112

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

목록 목록이 있습니다.

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

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


확실히 이것이 가능해야합니다 .. 아마도 새 버전에서 ...
ZEE

1
문을 실행할 수는 없지만 람다 함수에서 함수를 호출 할 수 있으므로 비 파이썬 더티 핵 lambda x: sort(x) OR x[1]이 작동합니다. 여기서 OR는 첫 번째 인수 (반환 값 None)를 부울 (=> False)로 평가 하고이 경우 OR 두 번째 인수를 반환합니다. 그러나 대답에서 알 수 있듯이 람다를 피하는 것이 좋습니다.
Max

답변:


136

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

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

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

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

map(second_lowest, lst)

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

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

3
heapq 모듈에서 발견되는 O (n) 솔루션에 대해 옳지 않다고 생각합니다. 여기서하는 일은 목록을 힙 정렬하는 것입니다. 이것은 O (n log n)이고 가장 작은 요소를 찾는 것입니다.
avpx 2012

8
문서 ( docs.python.org/2/library/heapq.html#heapq.nsmallest )는 실제로 heapq.nsmallest ()를 사용하는 것이 sorted ()를 사용하는 것보다 덜 효율적일 수 있다고 경고하므로 측정 만 해당 솔루션을 알 수 있습니다. 귀하의 경우 가장 빠릅니다. 그러나 heapq.nsmallest ()는 O (k * log (n) + n)의 복잡성을 가지고 있다고 생각합니다. n은 목록의 길이이고 k는 추출하려는 가장 작은 항목의 수입니다. O (n)은 목록을 힙화하고 k x O (log (n))는 k 항목을 팝합니다. 이것은 특히 작은 k의 경우 O (n * log (n))보다 낫습니다.
Vortexfive 2013-04-26

2
@Vortexfive 및 for constant k(여기서는 '두 번째로 낮은 값') O(k*log(n)+n)는 다음과 같이 단순화됩니다.O(n)
Duncan

5
기술적으로 한 줄짜리 람다도 필요하지 않지만 확실히 더 편리합니다. 나중에 더 나은 람다 지원이 추가되기를 바랍니다.
James

1
@avpx : 힙 정렬이 아닙니다. 전체 목록을 힙화하고 힙 정렬이 수행하는 것처럼 모든 요소를 ​​팝하는 대신 표시된 가장 작은 항목 2 개의 2 요소 힙만 유지합니다.
user2357112 모니카 지원

81

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

예 :

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

9
명확히하기 위해 함수 호출은 Python에서 명령문으로 간주되지 않고 표현식입니다. 따라서이 목록은 표현식 목록 일 뿐이며 모두 None.
Yawar

람다에 전달 된 컬렉션을 동적으로 분석 할 때 인터프리터가 호출 가능한 서명을 감지 하고 실행 하기 때문에 이것이 작동한다고 생각합니다 .-> lambda x : [print (x), print (x + 1), print (x +2)]
ZEE

5
더 나은 방법 : 람다 x : [f1 (x), f2 (x)] [-1], 예상대로 계산 결과를 마지막 표현식으로 반환합니다.
Anton Ovsyannikov

22

여기 시간 여행자. 일반적으로 람다 내에 여러 문을 포함하려면 다른 람다를 해당 람다에 대한 인수로 전달할 수 있습니다.

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

7

다음 과 같이 정렬 된 함수를 사용 합니다.

map(lambda x: sorted(x)[1],lst)

아 감사합니다. (함수에 대한 설명이 포함 된 이름입니다!) 람다 부분 내의 다중 문에 대해 여전히 궁금합니다. 가능한?
ottodidakt

1
아니요, "람다 형식으로 만든 함수는 문을 포함 할 수 없습니다." docs.python.org/reference/expressions.html#lambda
alex vasi

1
-1 : 목록 이해력 대신 람다와지도? 별로 비단뱀 같지 않습니다.
nikow

@nikow [x [1] for x in sorted (list)]-파이썬 방식?
RaGa__M

@Explorer_N : 목록을 정렬 할 필요가 없지만 현재 문제에서 목록 의 요소 (목록)를 정렬해야합니다. 오히려 : [sorted(x)[1] for x in list_of_lists].
Max

6

실제로 파이썬의 람다 식에 여러 문을 가질 수 있습니다. 완전히 사소한 것은 아니지만 귀하의 예에서는 다음과 같이 작동합니다.

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


4

파이썬에서 여러 문장을 하나의 문장으로 결합하는 해키 방법은 "and"키워드를 단락 연산자로 사용하는 것입니다. 그런 다음이 단일 문을 람다 식의 일부로 직접 사용할 수 있습니다.

이것은 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'또는 None을 반환하기 때문에 'and'대신 'or'를 사용하는 것이 좋습니다. 그런 다음 위의 예에서 래퍼 함수를 ​​제거 할 수 있습니다.

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

junky("a", "b")

'and'연산자는 첫 번째 0 반환 값에 도달 할 때까지 표현식을 평가합니다. 그 후 단락됩니다. 1과 1, 0과 1은 1과 1과 0을 평가하고 1을 떨어 뜨립니다.

'또는'연산은 0이 아닌 첫 번째 반환 값에 도달 할 때까지 표현식을 평가합니다. 그 후 단락됩니다.

0 또는 0 또는 1 또는 0은 0 또는 0 또는 1을 평가하고 0을 삭제합니다.


3

또는 람다를 피하고 목록 대신 생성기를 사용하려는 경우 :

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


2

영광 스럽지만 끔찍한 해킹을 소개하겠습니다.

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]



1

sort 또는 heapq를 사용하는 대신 min 및 index를 사용하여 O (n) 시간에 수행 할 수 있습니다.

먼저 원래 목록의 최소값을 제외한 모든 항목의 새 목록을 만듭니다.

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]

1

이것이 바로 Monadbind기능 이 사용되는 것입니다.

bind함수를 사용하면 여러 람다를 하나의 람다로 결합 할 수 있으며 각 람다는 문을 나타냅니다.


1

실제로 람다에서 여러 문을 사용할 수있는 방법이 있습니다. 내 해결책은 다음과 같습니다.

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

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

map(x, lst)

내부 코드는 exec지적인 IDE로 크션 수없는
javadba

0

예. 이런 식으로 정의하고 다음으로 여러 표현식을 래핑 할 수 있습니다.

계획 시작 :

시작 = 람다 * x : x [-1]

일반적인 Lisp 예 :

progn = 람다 * x : x [-1]


0

람다 함수를 사용하지 않고 더 나은 솔루션이 있습니다. 하지만 정말로 람다 함수를 사용하고 싶다면 여러 문장을 처리하는 일반적인 해결책이 있습니다 : map (lambda x : x [1] if (x.sort ()) else x [1], lst)

당신은 진술이 무엇을 반환하는지 정말로 신경 쓰지 않습니다.


0

네 가능합니다. 아래 코드 스 니펫을 시도하십시오.

x = [('human', 1), ('i', 2), ('am', 1), ('.', 1), ('love', 1), ('python', 3), ('', 1),
  ('run', 1), ('is', 2), ('robust', 1), ('hello', 1), ('spark', 2), ('to', 1), ('analysis', 2), ('on', 1), ('big', 1), ('data', 1), ('with', 1), ('analysis', 1), ('great', 1)
]

rdd_filter = rdd1_word_cnt_sum.filter(lambda x: 'python' in x or 'human' in x or 'big' in x)
rdd_filter.collect()

-1

또 다른 솔루션을 제공 할 것입니다. 람다가 함수를 호출하도록합니다.

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

7
더 나은 : junky = multiple_statements.
Solomon Ucko 2018
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.