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?
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).
A lambda function can take any number of arguments, but can only have one expression.
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.
You can use as many arguments as you want in a lambda function, but it can have only one expression.
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)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With