Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Index out of range when using lambda [duplicate]

Tags:

python

lambda

I'm a little confused about lambda operators in Python right now. The following (working) code sorts a list of tuples after the number of occurrences of a tuples first element over the first elements of all tuples:

tuples = [(2, 1, 8, 4), (3, 4, 8, 1), (3, 8, 1, 4), (4, 1, 8, 3),
              (4, 8, 1, 3), (8, 8, 3, 1), (8, 1, 3, 4), (8, 4, 1, 3),
              (8, 4, 3, 1)]

temp = list(zip(*tuples))    
tuples.sort(key=lambda x: temp[0].count(x[0])
                ,reverse=True)

print(tuples)

However, if I now try to skip the creating of "temp", i.e write this:

tuples = [(2, 1, 8, 4), (3, 4, 8, 1), (3, 8, 1, 4), (4, 1, 8, 3),
              (4, 8, 1, 3), (8, 8, 3, 1), (8, 1, 3, 4), (8, 4, 1, 3),
              (8, 4, 3, 1)]

tuples.sort(key=lambda x: list(zip(*tuples))[0].count(x[0])
                ,reverse=True)

print(tuples)

It throws an error:

Traceback (most recent call last):
  File "E:\Python-Programms\Sorting", line 6, in <module>
    ,reverse=True)
  File "E:\Python-Programms\Sorting", line 5, in <lambda>
    tuples.sort(key=lambda x: list(zip(*tuples)) [0].count(x[0])
IndexError: list index out of range

Why does this error occur?

like image 616
Sanitiy Avatar asked Jul 01 '17 21:07

Sanitiy


People also ask

Can Lambda return 2 values?

That's not more than one return, it's not even a single return with multiple values. It's one return with one value (which happens to be a tuple).

Can Lambda take two arguments?

A lambda function can take any number of arguments, but can only have one expression.

Can lambda function be reused in Python?

Can we reuse the lambda function? I guess the answer is yes because in the below example I can reuse the same lambda function to add the number to the existing numbers.

How many arguments can be passed to Lambda?

You can use as many arguments as you want in a lambda function, but it can have only one expression.


1 Answers

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)
like image 197
Moses Koledoye Avatar answered Sep 23 '22 09:09

Moses Koledoye