Index out of range when using lambda

The list

list(zip(*tuples))

in your lambda function is not a constant one - it evaluates again and again in every sorting step - every time when your lambda function is called.

1st sorting step is OK - the lambda function is exactly what you wanted. But then raises a problem.

The tuples list is during sorting in an unstable state, maybe empty, maybe something else - the sorting algorithm has freedom in it. Its only duty is so that the sorted list will be in the right state after performing the complete sort.

2nd sorting step evaluates the value of your lambda function on the basis of this unstable list - who knows its current value?

So using sorted list itself in the key function is not a very happy decision.


If you used a vanilla function and printed the list while it is being sorted, you'll notice the list is cleared out during the sort operation (AFAIK this applies to CPython). There isn't an index zero for an empty list:

def f(x):
  print (tuples)
  return ...

tuples.sort(key=f ,reverse=True)

[]
[]
[]
[]
[]
[]
[]
[]
[]

A peek into the CPython source leaves us with a useful comment that explains this behaviour:

static PyObject *
list_sort_impl(PyListObject *self, PyObject *keyfunc, int reverse)
{
    ...
    /* The list is temporarily made empty, so that mutations performed
     * by comparison functions can't affect the slice of memory we're
     * sorting (allowing mutations during sorting is a core-dump
     * factory, since ob_item may change).
     */
    ...
}

To your original problem, instead of calling list.count repeatedly, which is very inefficient, you can build a counter and then use that for sorting:

from collections import Counter

c = Counter([x[0] for x in tuples])
tuples.sort(key=lambda x: c[x[0]], reverse=True)

Tags:

Python

Lambda