tags:

views:

502

answers:

3

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)

+2  A: 

Use sorted function, like this:

map(lambda x: sorted(x)[1],lst)
alex vasi
ah.Thanks.(what a descriptive name for the function!)Still curious about the multiple statement within lambda part. Possible?
bagheera
Nope, "functions created with lambda forms cannot contain statements". http://docs.python.org/reference/expressions.html#lambda
alex vasi
-1: lambda and map instead of list comprehensions? Not very pythonic.
nikow
+3  A: 

Or if you want to avoid lambda and have a generator instead of a list:

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

odwl
+10  A: 

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. ie:

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 poinst 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]
Brian
+1: You don't need a lambda.
S.Lott