python lambda表达式中可以有多个语句吗?


112

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

但是排序不会连锁。(返回无)

不允许这样的事情:

map(lambda x: sort(x); x[1],lst) #hence the multiple statement question

有没有一种方法可以在python中使用map来执行此操作,而无需定义命名函数?(例如,使用Ruby中的匿名块很容易)


确保这应该是可能的..也许是新版本...
ZEE

1
您无法执行语句,但可以在lambda函数中调用函数,因此可以使用非Python肮脏的技巧lambda x: sort(x) OR x[1]:在此OR将其第一个参数(返回值None)评估为bool(=> False),在这种情况下,OR返回其第二个参数。但是正如答案所说,最好避免使用lambda。
最多

Answers:


136

从您的具体问题到更一般的问题,我可以在这里提供几种不同的答案。因此,从最具体到最一般:

问:能否在lambda中放入多个语句?

:不但是您实际上不需要使用lambda。您可以将语句放在a中def。即:

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

map(second_lowest, lst)

问:您可以通过对列表进行排序从lambda中获取第二低的项目吗?

答:是的。正如alex的答案所指出的那样,sorted()是sort的一种版本,它创建一个新列表,而不是就地排序,并且可以被链接。请注意,这可能是您应该使用的-地图在原始列表上产生副作用是不好的做法。

问:如何从一系列列表中的每个列表中获取第二低的项目?

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)

通常也认为使用列表理解更为清晰,这完全避免了lambda:

[heapq.nsmallest(x,2)[1] for x in list_of_lists]

3
我认为您对在heapq模块中找到的O(n)解决方案不正确。您要做的就是对列表进行堆排序,即O(n log n),然后找到最小的元素。
avpx

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次O(log(n))弹出k个项目。这比O(n * log(n))更好,特别是对于小k。
Vortexfive

2
@Vortexfive和常量k(如此处的“第二低”)O(k*log(n)+n)简化为O(n)
Duncan

5
从技术上讲,您也不需要单层的lambda,但这当然更方便。希望稍后会提供更好的lambda支持。
2014年

1
@avpx:这不是堆排序。我们只保留看到的2个最小项的2元素堆,而不是像堆堆那样堆放整个列表并弹出所有元素。
user2357112支持Monica

80

将语句放在列表中可能会模拟多个语句:

例如:

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

9
为了澄清起见,函数调用在Python中不被视为语句,它们是表达式。因此,此列表只是一个表达式列表,可能都是None
Yawar

我认为这是可行的,因为在动态分析传递给lambda的集合时,解释器会检测可调用的签名并执行它们……您可以使用-> lambda x进行测试: +2)]
ZEE

5
更好的是:lambda x:[f1(x),f2(x)] [-1],它可能会从预期的最后一个表达式返回计算结果。
安东·奥夫辛尼科夫

22

时光旅行者在这里。如果通常要在一个lambda中包含多个语句,则可以将其他lambda作为该lambda的参数传递。

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

您实际上不能有多个语句,但是可以通过将lambda传递给lambda来模拟该语句。

编辑:时间旅行者回来了!您还可以将布尔表达式的行为(记住短路规则和真实性)用于链式操作。使用三元运算符可为您提供更多功能。同样,您不能有多个语句,但是您当然可以有许多函数调用。此示例对一堆数据进行了任意处理,但是,它表明您可以做一些有趣的事情。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)

啊。谢谢。(该函数的描述性名称!)仍然对lambda部分中的多语句感到好奇。可能?
09年

1
不,“用lambda表单创建的函数不能包含语句”。docs.python.org/reference/expressions.html#lambda
Alex vasi 09年

1
-1:lambda和map而不是列表推导?不是很pythonic。
尼科夫

@nikow [x [1] for x in sorted(list)]-pythonic方法吗?
RaGa__M

@Explorer_N:在当前问题中,不是必须对列表进行排序,但是必须对列表的元素(即列表)进行排序。而是:[sorted(x)[1] for x in list_of_lists]
最多

6

实际上,您可以在python中的lambda表达式中包含多个语句。这并不简单,但在您的示例中,以下工作原理:

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

在Python中将多个语句组合成单个语句的Hacky方法是使用“ and”关键字作为短路运算符。然后,您可以将此单个语句直接用作lambda表达式的一部分。

这类似于在shell语言(例如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")

“ and”运算将对表达式进行求值,直到达到第一个零返回值为止。之后短路。1和1以及0和1求值:1和1和0并丢弃1

“或”运算将对表达式进行求值,直到达到第一个非零返回值为止。之后短路。

0或0或1或0计算0或0或1,并丢弃0


3

或者,如果您想避免使用lambda并使用生成器而不是列表:

(第一个col的sorted(col)[1])


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

您可以使用min和index而不是使用sort或heapq在O(n)时间内完成此操作。

首先创建除原始列表的最小值以外的所有内容的新列表:

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

然后取新列表的最小值:

second_smallest = min(new_list)

现在,所有这些都放在一个lambda中:

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

这也正是bind在函数单子的用途。

使用此bind功能,您可以将多个lambda组合为一个lambda,每个lambda代表一条语句。


1

实际上,有一种方法可以在lambda中使用多个语句。这是我的解决方案:

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

是。您可以用这种方式定义它,然后用以下代码包装多个表达式:

计划开始:

开始= lambda * x:x [-1]

Lisp常见问题:

progn = lambda * x:x [-1]


0

没有使用lambda函数的更好的解决方案。但是,如果我们真的想使用lambda函数,则这是处理多个语句的通用解决方案: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

我将给您另一个解决方案,使您的lambda调用一个函数。

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
所罗门·乌科
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.