是否有可能在python lambda表达式中有多个语句?

时间:2009-05-14 09:31:34

标签: 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)

但排序不会链。 (返回无)

这两种情况都不允许:

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

有没有办法在python中使用map而不是而不定义命名函数? (例如,在ruby中使用匿名块很容易)

18 个答案:

答案 0 :(得分:109)

我可以在这里给出几个不同的答案,从您的具体问题到更一般的问题。所以从最具体到最一般:

问。你能在lambda中放多个语句吗?

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

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

map(second_lowest, lst)

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

A。是的。当alex's answer poinst out时,sorted()是排序的一个版本,它创建一个新列表,而不是就地排序,并且可以链接。请注意,这可能是你应该使用的 - 你的地图在原始列表上有副作用是不好的做法。

问。如何从列表序列中的每个列表中获取第二低的项目。

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)

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

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

答案 1 :(得分:70)

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

E.g:

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

答案 2 :(得分:18)

时间旅行者在这里。如果您通常希望在lambda中包含多个语句,则可以将其他lambda作为参数传递给该lambda。

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

你实际上不能有多个语句,但你可以通过将lambdas传递给lambdas来模拟它。

编辑:时间旅行者返回!您还可以滥用布尔表达式的行为(记住短路规则和真实性)到链操作。使用三元运算符可为您提供更强大的功能。同样,你不能有多个语句,但你当然可以有很多函数调用。这个例子用一堆数据做了一些任意的垃圾,但是,它表明你可以做一些有趣的事情。 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)]

答案 3 :(得分:7)

使用sorted function,如下所示:

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

答案 4 :(得分:4)

从这里使用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]

答案 5 :(得分:4)

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

答案 6 :(得分:3)

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

(对于第一列中的col的排序(col)[1]

答案 7 :(得分:3)

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

这类似于使用“&&”作为shell语言中的短路运算符,如bash。

另请注意:您始终可以通过包装函数来修复函数语句以返回true值。

示例:

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。然后你可以摆脱上面例子中的包装函数:

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

junky("a", "b")

'和'操作将评估表达式,直到它达到第一个零返回值。之后它会短路。   1和1和0和1   评估:1和1和0,并下降1

'或'operation将评估表达式,直到它达到第一个非零返回值。之后它会短路。

0或0或1或0   评估0或0或1,并下降0

答案 8 :(得分:2)

我会给你另一个解决方案,让你的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');

答案 9 :(得分:1)

这正是Monadbind函数的用途。

使用bind函数,您可以将多个lambda组合成一个lambda,每个lambda代表一个语句。

答案 10 :(得分: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]

答案 11 :(得分:1)

让我向你展示一个光荣但可怕的黑客:

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]

答案 12 :(得分: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)

答案 13 :(得分:1)

在分析了上面提供的所有解决方案之后,我想到了这种组合,这似乎对我最有用的广告:

func = lambda *args, **kwargs: "return value" if [
    print("function 1..."),
    print("function n"),
    ["for loop" for x in range(10)]
] else None

不是很漂亮吗? 请记住,列表中必须包含某些内容,因此它具有True价值。 另一件事是,列表可以替换为set,看起来更像C样式代码,但是在这种情况下,您不能将列表放在其中,因为它们不是hashabe

答案 14 :(得分:0)

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

计划开始:

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

常见的Lisp错误:

progn = lambda * x:x [-1]

答案 15 :(得分:0)

有一些更好的解决方案,而不使用lambda函数。但是,如果我们真的想使用lambda函数,则可以使用以下通用解决方案来处理多个语句:   map(lambda x:x [1] if(x.sort())else x [1],lst)

您实际上并不在乎语句返回的内容。

答案 16 :(得分: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()

答案 17 :(得分:0)

演示lambda x:[f1(),f2()]效果,使我们能够在lambda中执行多个功能。如果您真的想缩小代码,它还会演示单行(如果其他情况)。

  • 请注意,f1()也可以是lambda函数(递归lambda或 lambda内的lambda)。并且内部lambda可以是以下语句/函数 您的选择。
  • 您还可以输入exec('statement'),例如lambda x:[exec('a=[1]'),exec('b=2')]

touch(linux)命令的python实现,如果不存在空文件,则创建空文件。

def touch(fpath):
    check= os.path.exists(fpath)
    (lambda fname1:[open(fname1,"w+",errors="ignore").write(""),print('Touched',fname1)] 
    if not check else None) (fpath)

将打印[触摸fpath],其中fpath是输入的文件路径。如果文件已经存在,将不执行任何操作。

(lambda x: [ f(x), f2(x) ] ) (inp) <-我们将'inp'作为输入传递给lambda,在本例中为fpath