按列表中元素的出现次数对列表进行排序

时间:2022-02-26 20:24:55

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强加的限制,该限制本身无法查看。