4

Let's say I define a list of lists lol:

lol = [['malasia', 0.02, 56.3], ['chile', 0.03, 34.9],
       ['hungria', 0.01, 45.9], ['ahumada', 0.001, 1]]

Then,

lol.sort(lambda x, y: cmp(y[2], x[2]))

orders lol by the last element of each sublist...


I'm just trying to understand the component parts of the sort:

  • cmp(y,x) compares to numbers and returns -1 (y less x), 0 (x equals y), or 1 (y bigger x).

  • lambda is defining a function over the last elements of each list? Then lambda inside a sort? I'm confused- could anybody explain what the lambda function does?

1
  • The cmp parameter is only supported for backward compatibility. It's been removed from Python3. Always use key= instead. If you have a tricky case where a key function won't work use functools.cmp_to_key helper Commented Mar 13, 2013 at 22:25

4 Answers 4

4

Then lambda inside a sort? I am lost!

Basically, when sort() needs to compare two elements, it calls the lambda function and uses its result to determine which of the two elements should come first. This is all there is to it.

Sign up to request clarification or add additional context in comments.

4 Comments

The OP should note that this is really inefficient, as it is called once for each pair of elements. Use a key function instead, as this is called just once for each element.
@DanielRoseman: I don't get you. Could you elaborate it pls? As far as im understanding it, the key-function is always comparing two elements, how else should it determine if the other element is before or after one-self. And btw, i thought that timsort did it's work autmagically behind the curtains with the key-func, reducing "double"-compares, but i never really dived into it deeply.
@DonQuestion The point of the key function is that it runs once for each element, before the sort itself begins, and provides a simple value that can be used in the comparison. The sort then, in effect, sorts the key values, rather than the elements themselves. Compare that with the cmp, where for each comparison that must be done, the cmp function must be called.
@DanielRoseman: So basically, every item in the iterable is touched by the key-func in a pre-run, to be touched in a second run by a compare function? (I did a little peek into the source, it seems it's basically a call of some function in Objects/listobject.c, but i couldn't relly graps which one.)
4

This is actually better done using the key argument to sort, cmp is somewhat outdated.

For example:

lol.sort(key=lambda x: x[2])

(you could also use x[-1] to mean the last element of the list)

You are creating the lambda and passing it into the sort function. You could also write it like this:

get_third_element = lambda x: x[2]
lol.sort(key=get_third_element)

Or to make it even easier to understand:

def get_third_element(x):
    return x[2]

lol.sort(key=get_third_element)

There's no reason you can't pass a function into another function as an argument!

Comments

3

The lambda function in your example determines which item comes first.

In a "classical"-situation it would simply calculate x-y: if the result is negative it means that x is smaller then y and therefore comes before y.

Additionally you may pass a reverse-parameter to the sort-method, which would reverse=True the order.

Your "sort"-function is in this case the cmp-function in the "lambda-wrapper". Therein you swap the order of x with y and use the 3rd argument, which means it sorts in a reversed order(x/y-swap) and does it by comparing all the 3rd arguments(x[2]).

Regarding your 2nd bullet:

... could anybody explain what the lambda function does"

If your asking what a lambda-function is: It's an anonymous light-weight inline function. Anonymous means it doesn't have an identifier. (But you could assign one. e.g.: sqr = lambda x : x**2 which you could use now like any other function: y = sqr(2))

Normal function: def name(arg): vs lambda-function: lambda   arg: ret_value
                  ^    ^    ^                          ^   ^  ^       ^
                  a)   b)   c)                         a)  b) c)      d)
  • a) keyword marking the following as a normal/lambda-function
  • b) function-name in case of the lambda functio "missing" therefore anonymous
  • c) function arguments: normal function ->brackets, lambda-function -> without
  • d) return value - in case of the normal function omitted, because must be explicitly returned with return. (without explicit return it delivers None) The lambda implicitly returns the result of the evaluation on the right side of the colon.

Your example of the sort-function use is a typical use-case for lambda-functions. They are used as "throw-away" functions, which you may inline without to create a own normal function.

A more "pythonic" variation would be something like:

from operator import itemgetter

keyfunc = itemgetter(2) # takes the 3rd argument from an itterable
sorted_list = sorted(lol, key=keyfunc, reverse=True)

4 Comments

The lambda function is not related to the key parameter (not function) at all. It simply defines a generic function object without associating it with a variable. You can use it in contexts entirely separate from sorting,. For example, to print "hello", you can use: (lambda x: print(x))("hi")
a) Returning None is not equivalent to throwing an exception. b) It is possible to write lambda functions unrelated to the key parameter that work in both python 2.x and 3.x, eg. lambda x,y: x+y c) The purpose is to demonstrate that lambda functions can be used for purposes entirely unrelated to sorting, and that it is by no means known as "the key function". A particular lambda function is simply being passed as the key parameter.
@Asad: Btw: I don't understand your bogus argument: "... key parameter (not function)"! But we are on the same page, that the key-argument hast to be at least a callable if you want to generalize away from a function?
The example I posted was specifically intended not to work with sorting. The whole point was to show that the lambda function is independent of sorting, and therefore calling it the key function is wrong. You've corrected that, which is great, but I don't get what you're arguing about. "But you are not completely right either" <- yes I was. I only had one point, which was that lambda function != key function.
1

lambda is of type "function"
So your

lambda x, y : cmp(y[2], x[2])

is equal to

def f(x, y):
    return cmp(y[2], x[2])

The sort takes a function, and when it need to compare two elements, it would call that lambda function, which would return the value of cmp(y[2], x[2])

So this sort would sort your list in this way: whenever it meets two element, it would fetch the last values in the "triples" and compare them to determine the precedence.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.