list.sort(key=list.count)在Python3.x中是如何工作的?
我想根据元素的频率对数字列表进行排序。 (我找到了几种方法。) 在我的探索过程中,我尝试了下面的例子 问题:list.sort(key=list.count)是如何工作的?是否可以在list.sort()期间使用list.count() 我了解到,在排序之前,会对列表中的每个元素计算key函数,这些值在排序期间用于比较 另外,我在某个地方读到,在sort()期间,列表有点被锁定。 (很抱歉,我现在找不到参考资料-在过去的几个小时里,我已经阅读了很多关于这个主题的博客和教程,包括Python文档和如何排序) 这就是一个例子list.sort(key=list.count)在Python3.x中是如何工作的?,python,python-3.x,list,sorting,Python,Python 3.x,List,Sorting,我想根据元素的频率对数字列表进行排序。 (我找到了几种方法。) 在我的探索过程中,我尝试了下面的例子 问题:list.sort(key=list.count)是如何工作的?是否可以在list.sort()期间使用list.count() 我了解到,在排序之前,会对列表中的每个元素计算key函数,这些值在排序期间用于比较 另外,我在某个地方读到,在sort()期间,列表有点被锁定。 (很抱歉,我现在找不到参考资料-在过去的几个小时里,我已经阅读了很多关于这个主题的博客和教程,包括Python文档和
### Python 3.7 ###
data = [22, 11, 33, 99, 88, 77, 22, 44, 55, 44, 66, 22]
# sort by value
data.sort()
print(data)
>>> [11, 22, 22, 22, 33, 44, 44, 55, 66, 77, 88, 99]
# sort by frequency, i.e. list.count()
data.sort(key=data.count)
print(data)
>>> [11, 22, 22, 22, 33, 44, 44, 55, 66, 77, 88, 99]
# expected >>> [11, 33, 55, 66, 77, 88, 99, 44, 44, 22, 22, 22]
# but no change, the value-sorted list is printed
# or
data.sort(key=lambda e: data.count(e))
print(data)
>>> [11, 22, 22, 22, 33, 44, 44, 55, 66, 77, 88, 99]
# expected >>> [11, 33, 55, 66, 77, 88, 99, 44, 44, 22, 22, 22]
# but no change, the value-sorted list is printed
注意:没有错误消息
作为补充,我想提到的是,以下工作与预期相符
max(data, key=data.count)
当然,这也给出了预期的结果
print(sorted(data, key=data.count))
>>> [11, 33, 55, 66, 77, 88, 99, 44, 44, 22, 22, 22]
根据文档,sorted()和sort()应该返回相同的结果,不是吗
谢谢你的见解
编辑:
根据文件-据我所知:
- 为什么结果是实际返回的列表而不是我的期望
- 相比之下,为什么sorted()按预期工作
- 这是一个有趣的问题,我没有完整的答案,因为它在这里的源代码中的某个地方:
但是,通过使用以下功能作为键,您可以获得部分答案:
def count(e):
print(data)
return data.count(e)
如果这样做,您将看到它只打印“[]”。这意味着在就地排序过程中,可能是为了避免弄乱列表,列表现在指向一个空列表(即使引用本身数据没有更改)。因此data.count(e)始终等于0,并且列表保持不变
因此,在就地排序过程中使用列表的唯一方法是复制列表,例如:
data.sort(key=data.copy().count)
我要补充的是,这不会增加复制列表整个过程的成本,因为上面的行已经是O(n²log(n))。实际上,对列表中的每个元素调用count是一个非常糟糕的主意。一种有效的O(n log(n))方法是:
nb_occ={}
for x in data:
nb_occ[x]=nb_occ.get(x,0)+1
data.sort(key=nb_occ.__getitem__)
编辑:请参阅juanpa.arrivillaga的答案,这种行为实际上记录在排序方法文档中。好,根据:
CPython实现细节:在对列表进行排序时
试图改变甚至检查列表的效果是
未定义Python的C实现使列表显示为空
持续时间,如果可以检测到列表
在排序过程中发生了变异
如果是粗体部分,那么对于任何元素,
data.count
将返回0
,排序不会改变列表的顺序。@juanpa.arrivillaga我不明白背景中发生了什么-当然这不是我所怀疑的,这就是我包含实际输出和预期输出的原因。用我期望的解释来扩展问题。啊,我读得不够仔细。这很奇怪,看起来像一只虫子。另一方面,您应该注意到,这是非常低效的,它将排序算法降级为O(N^2),而不是O(N*logn)以挑剔措辞:-)实际上,排序算法实现的效率保持不变。这是元素“权重”的计算(在排序实际开始之前)——这里给出了答案中的一些其他示例,我假设开发人员在实现list.count()时也做得很好。查找源代码和/或基准测试时要了解的内容。list.count
是一个O(n)操作,因此在某些列表中为x调用[x.count()
就是一个O(n**2)操作。因此,它肯定会影响算法的效率。如果您不想这样做,请从集合导入计数器执行类似于的操作;计数=计数器(某些列表);一些_list.sort(key=counts.get)
我同意你的观点,谢谢你的解释。我只是想更准确(可能不够准确)地将频率计算与排序分开,因为它们一个接一个地发生。请您添加并解释一下!实际上,我所做的是创建了两个列表,分别是a和s,在其中添加了数据列表成员及其频率。然后,我将这些列表(a和s)作为键值对添加到dict(p)中。现在列表没有排序,所以现在我使用了内置的排序函数来根据值对dict进行排序。感谢您的解释!这是一种有效的方法吗
nb_occ={}
for x in data:
nb_occ[x]=nb_occ.get(x,0)+1
data.sort(key=nb_occ.__getitem__)