我现在对Python中的lambda运算符有点困惑。以下(工作)代码在元组的第一个元素出现在所有元组的第一个元素之后对元组列表进行排序:
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)
但是,如果我现在试图跳过“临时”的创建,即写下这个:
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)
它会抛出错误:
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
为什么会出现此错误?
答案 0 :(得分:12)
如果您使用了vanilla函数并在排序时打印了列表,您会注意到在排序操作期间清除了列表(AFAIK适用于CPython)。空列表的索引号为零:
def f(x):
print (tuples)
return ...
tuples.sort(key=f ,reverse=True)
[]
[]
[]
[]
[]
[]
[]
[]
[]
查看CPython源代码会给我们留下一个解释此行为的有用注释:
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).
*/
...
}
对于你原来的问题,你不是反复调用list.count
,而是非常低效,你可以建立一个计数器,然后用它来进行排序:
from collections import Counter
c = Counter([x[0] for x in tuples])
tuples.sort(key=lambda x: c[x[0]], reverse=True)
答案 1 :(得分:4)
列表
list(zip(*tuples))
lambda
函数中的 不是常量 - 它会在每个排序步骤中反复评估 - 每次lambda
时函数被调用。
1 st 排序步骤没问题 - lambda
功能正是您想要的。但后来提出了一个问题。
tuples
列表是在不稳定状态中排序,可能是空的,也许是别的 - 排序算法在其中具有自由度。它的唯一职责是在执行完整排序后排序列表处于正确的状态。
2 nd 排序步骤根据 unstable 列表评估lambda
函数的值 - 谁知道它的当前值?
因此在key
函数中使用排序列表本身并不是一个非常愉快的决定。