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]]
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
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
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 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]
Use sorted function, like this:
map(lambda x: sorted(x)[1],lst)