I want to sort a list by the number of occurrences of the elements in the list.
When I use this form:
我想按列表中元素的出现次数对列表进行排序。当我使用这个表格时:
A=[2,1,3,4,2,2,3]
A.sort(key=lambda x:A.count(x))
print(A)
the result is not what I want: [2, 1, 3, 4, 2, 2, 3]
.
But, when I write like it using sorted
:
结果不是我想要的:[2,1,3,4,2,2,3]。但是,当我使用sorted编写它时:
B=sorted(A,key=lambda x:A.count(x))
print(B)
the result is right: [1, 4, 3, 3, 2, 2, 2]
.
what's the reason for this behavior?
结果是正确的:[1,4,3,3,2,2,2]。这种行为的原因是什么?
4 个解决方案
#1
17
This is by design and intentional. CPython temporarily "disallows" access to the list while the list is being sorted in place, the behavior is documented here:
这是设计和有意的。当列表正在排序时,CPython暂时“禁止”访问列表,此行为记录在此处:
CPython implementation detail: While a list is being sorted, the effect of attempting to mutate, or even inspect, the list is undefined. The C implementation of Python makes the list appear empty for the duration, and raises ValueError if it can detect that the list has been mutated during a sort.
CPython实现细节:在对列表进行排序时,尝试变异甚至检查列表的效果是不确定的。 Python的C实现使得列表在持续时间内显示为空,如果它可以检测到列表在排序期间已经变异,则会引发ValueError。
You can inspect that by printing A
inside the key function - you'll get an empty list:
您可以通过在键功能中打印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)
But, if you do that for sorted()
:
但是,如果你为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]
It is also documented inside the sort()
implementation:
它也在sort()实现中记录:
/* 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).
*/.
#2
6
It seems that A
is changed during the in-place sort process, so you cannot rely on the value of A
during the sort process.
似乎A在就地排序过程中发生了变化,因此在排序过程中不能依赖A的值。
Making a copy also works.
制作副本也有效。
A=[2,1,3,4,2,2,3]
B=A[:]
A.sort(key=lambda x:B.count(x))
print(A)
Confirmed by this line in python documentation
在python文档中通过这一行确认
CPython implementation detail: While a list is being sorted, the effect of attempting to mutate, or even inspect, the list is undefined. The C implementation of Python makes the list appear empty for the duration, and raises ValueError if it can detect that the list has been mutated during a sort.
CPython实现细节:在对列表进行排序时,尝试变异甚至检查列表的效果是不确定的。 Python的C实现使得列表在持续时间内显示为空,如果它可以检测到列表在排序期间已经变异,则会引发ValueError。
#3
2
I believe it's because A.sort
is modifying the list in place underneath while computing. sorted()
doesn't modify the list and returns therefore a correct result.
我相信这是因为A.sort在计算时正在修改下面的列表。 sorted()不会修改列表并返回正确的结果。
#4
1
The built-in sorted
creates a list out of the sequence provided and then sorts that based on the key argument (omitting error checking):
内置的sorted会根据提供的序列创建一个列表,然后根据键参数对其进行排序(省略错误检查):
/* 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);
This essentially translates to something like what Jean provided in his answer:
这基本上转化为Jean在答案中提供的内容:
B = list(A)
B.sort(key=lambda x: A.count(x))
By making that copy B
and referencing A
in the key
function, this removes the restriction imposed by A.sort
which can't peek in itself.
通过在关键函数中创建该副本B并引用A,这消除了A.sort强加的限制,该限制本身无法查看。
#1
17
This is by design and intentional. CPython temporarily "disallows" access to the list while the list is being sorted in place, the behavior is documented here:
这是设计和有意的。当列表正在排序时,CPython暂时“禁止”访问列表,此行为记录在此处:
CPython implementation detail: While a list is being sorted, the effect of attempting to mutate, or even inspect, the list is undefined. The C implementation of Python makes the list appear empty for the duration, and raises ValueError if it can detect that the list has been mutated during a sort.
CPython实现细节:在对列表进行排序时,尝试变异甚至检查列表的效果是不确定的。 Python的C实现使得列表在持续时间内显示为空,如果它可以检测到列表在排序期间已经变异,则会引发ValueError。
You can inspect that by printing A
inside the key function - you'll get an empty list:
您可以通过在键功能中打印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)
But, if you do that for sorted()
:
但是,如果你为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]
It is also documented inside the sort()
implementation:
它也在sort()实现中记录:
/* 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).
*/.
#2
6
It seems that A
is changed during the in-place sort process, so you cannot rely on the value of A
during the sort process.
似乎A在就地排序过程中发生了变化,因此在排序过程中不能依赖A的值。
Making a copy also works.
制作副本也有效。
A=[2,1,3,4,2,2,3]
B=A[:]
A.sort(key=lambda x:B.count(x))
print(A)
Confirmed by this line in python documentation
在python文档中通过这一行确认
CPython implementation detail: While a list is being sorted, the effect of attempting to mutate, or even inspect, the list is undefined. The C implementation of Python makes the list appear empty for the duration, and raises ValueError if it can detect that the list has been mutated during a sort.
CPython实现细节:在对列表进行排序时,尝试变异甚至检查列表的效果是不确定的。 Python的C实现使得列表在持续时间内显示为空,如果它可以检测到列表在排序期间已经变异,则会引发ValueError。
#3
2
I believe it's because A.sort
is modifying the list in place underneath while computing. sorted()
doesn't modify the list and returns therefore a correct result.
我相信这是因为A.sort在计算时正在修改下面的列表。 sorted()不会修改列表并返回正确的结果。
#4
1
The built-in sorted
creates a list out of the sequence provided and then sorts that based on the key argument (omitting error checking):
内置的sorted会根据提供的序列创建一个列表,然后根据键参数对其进行排序(省略错误检查):
/* 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);
This essentially translates to something like what Jean provided in his answer:
这基本上转化为Jean在答案中提供的内容:
B = list(A)
B.sort(key=lambda x: A.count(x))
By making that copy B
and referencing A
in the key
function, this removes the restriction imposed by A.sort
which can't peek in itself.
通过在关键函数中创建该副本B并引用A,这消除了A.sort强加的限制,该限制本身无法查看。