Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to have multiple statements in a python lambda expression?

Tags:

python

I am a python newbie trying to achieve the following:

I have a list of lists:

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

I want map lst into another list containing only the second smallest number from each sublist. So the result should be:

[345, 465, 333]

For example if I were just interested in the smallest number, I could do:

map(lambda x: min(x),lst)

I wish I could do this:

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

but sort does not chain. (returns None)

neither is something like this allowed:

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

Is there a way to do this with map in python but without defining a named function? (it is easy with anonymous blocks in ruby, for example)

like image 206
ottodidakt Avatar asked May 14 '09 09:05

ottodidakt


People also ask

Can Python lambda have multiple statements?

Lambda functions does not allow multiple statements, however, we can create two lambda functions and then call the other lambda function as a parameter to the first function.

Can lambda expressions contain multiple statements?

Statement lambdasThe body of a statement lambda can consist of any number of statements; however, in practice there are typically no more than two or three. Action<string> greet = name => { string greeting = $"Hello {name}!"; Console. WriteLine(greeting); }; greet("World"); // Output: // Hello World!

How many arguments can lambda take Python?

In Python, a lambda function is a single-line function declared with no name, which can have any number of arguments, but it can only have one expression.


3 Answers

There are several different answers I can give here, from your specific question to more general concerns. So from most specific to most general:

Q. Can you put multiple statements in a lambda?

A. No. But you don't actually need to use a lambda. You can put the statements in a def instead. i.e.:

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

map(second_lowest, lst)

Q. Can you get the second lowest item from a lambda by sorting the list?

A. Yes. As alex's answer points out, sorted() is a version of sort that creates a new list, rather than sorting in-place, and can be chained. Note that this is probably what you should be using - it's bad practice for your map to have side effects on the original list.

Q. How should I get the second lowest item from each list in a sequence of lists?

A. sorted(l)[1] is not actually the best way for this. It has O(N log(N)) complexity, while an O(n) solution exists. This can be found in the heapq module.

>>> import  heapq
>>> l = [5,2,6,8,3,5]
>>> heapq.nsmallest(l, 2)
[2, 3]

So just use:

map(lambda x: heapq.nsmallest(x,2)[1],  list_of_lists)

It's also usually considered clearer to use a list comprehension, which avoids the lambda altogether:

[heapq.nsmallest(x,2)[1] for x in list_of_lists]
like image 106
Brian Avatar answered Oct 19 '22 11:10

Brian


Putting the expressions in a list may simulate multiple expressions:

E.g.:

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

This will not work with statements.

like image 40
jmkg Avatar answered Oct 19 '22 11:10

jmkg


Time traveler here. If you generally want to have multiple statements within a lambda, you can pass other lambdas as arguments to that lambda.

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

You can't actually have multiple statements, but you can simulate that by passing lambdas to lambdas.

Edit: The time traveler returns! You can also abuse the behavior of boolean expressions (keeping in mind short-circuiting rules and truthiness) to chain operations. Using the ternary operator gives you even more power. Again, you can't have multiple statements, but you can of course have many function calls. This example does some arbitrary junk with a bunch of data, but, it shows that you can do some funny stuff. The print statements are examples of functions which return None (as does the .sort() method) but they also help show what the lambda is doing.

>>> (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)]
like image 33
2rs2ts Avatar answered Oct 19 '22 10:10

2rs2ts