我想按列表中元素的出现次数对列表进行排序 当我使用这个表格时:
A=[2,1,3,4,2,2,3]
A.sort(key=lambda x:A.count(x))
print(A)
结果不是我想要的:[2, 1, 3, 4, 2, 2, 3]
。
但是,当我使用sorted
编写它时:
B=sorted(A,key=lambda x:A.count(x))
print(B)
结果是正确的:[1, 4, 3, 3, 2, 2, 2]
。
这种行为的原因是什么?
答案 0 :(得分:17)
这是设计和有意的。 CPython暂时"不允许"在对列表进行排序时访问列表,行为为documented here:
CPython实现细节: 在对列表进行排序时, 试图改变甚至检查清单的效果是 undefined。 Python的C实现使列表显示为空 持续时间,如果可以检测到列表,则引发ValueError 在某种程度上已经发生了变异。
您可以通过在关键功能中打印A
来检查它 - 您将获得空列表:
In [2]: def key_function(x):
...: print(A, x)
...: return A.count(x)
...:
In [3]: A.sort(key=key_function)
([], 2)
([], 1)
([], 3)
([], 4)
([], 2)
([], 2)
([], 3)
但是,如果你为sorted()
执行此操作:
In [4]: sorted(A, key=key_function)
([2, 1, 3, 4, 2, 2, 3], 2)
([2, 1, 3, 4, 2, 2, 3], 1)
([2, 1, 3, 4, 2, 2, 3], 3)
([2, 1, 3, 4, 2, 2, 3], 4)
([2, 1, 3, 4, 2, 2, 3], 2)
([2, 1, 3, 4, 2, 2, 3], 2)
([2, 1, 3, 4, 2, 2, 3], 3)
Out[4]: [1, 4, 3, 3, 2, 2, 2]
它还记录在sort()
implementation:
/* 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).
*/.
答案 1 :(得分:6)
似乎A
在就地排序过程中发生了变化,因此您无法在排序过程中依赖A
的值。
制作副本也有效。
A=[2,1,3,4,2,2,3]
B=A[:]
A.sort(key=lambda x:B.count(x))
print(A)
中的这一行确认
CPython实现细节:在对列表进行排序时,尝试变异甚至检查列表的效果是未定义的。 Python的C实现使列表在持续时间内显示为空,如果它可以检测到列表在排序期间已经变异,则会引发ValueError。
答案 2 :(得分:2)
我相信它是因为A.sort
在计算时正在修改下面的列表。 sorted()
不修改列表并返回正确的结果。
答案 3 :(得分:1)
内置sorted
creates a list out of the sequence提供然后根据键参数对其进行排序(省略错误检查):
/* copy sequence provided */
newlist = PySequence_List(seq);
/* get list.sort for the list object */
callable = _PyObject_GetAttrId(newlist, &PyId_sort);
/* call it and then return later on */
v = _PyObject_FastCallKeywords(callable, args + 1, nargs - 1, kwnames);
这实际上转化为Jean在答案中提供的内容:
B = list(A)
B.sort(key=lambda x: A.count(x))
通过在B
函数中复制A
并引用key
,可以消除A.sort
强加的限制,而这种限制本身无法查看。