Quiero ordenar una lista por el número de ocurrencias de los elementos en la lista.
Cuando uso este formulario:
A=[2,1,3,4,2,2,3] A.sort(key=lambda x:A.count(x)) print(A) el resultado no es lo que quiero: [2, 1, 3, 4, 2, 2, 3] .
Pero, cuando escribo me gusta usando sorted :
B=sorted(A,key=lambda x:A.count(x)) print(B) el resultado es correcto: [1, 4, 3, 3, 2, 2, 2] .
¿Cuál es la razón de este comportamiento?
Esto es por diseño e intencional. CPython "no permite" temporalmente el acceso a la lista mientras la lista se ordena en su lugar, el comportamiento se documenta aquí :
Detalle de implementación de CPython: mientras se ordena una lista, el efecto de intentar mutar, o incluso inspeccionar, la lista no está definido. La implementación en C de Python hace que la lista parezca vacía durante el tiempo que dura y genera ValueError si puede detectar que la lista se ha mutado durante una ordenación.
Puede inspeccionar eso imprimiendo A dentro de la función clave; obtendrá una lista vací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) Pero, si haces eso para 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] También está documentado dentro de la implementación 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). */.Parece que A se cambia durante el proceso de clasificación en el lugar, por lo que no puede confiar en el valor de A durante el proceso de clasificación.
Hacer una copia también funciona.
A=[2,1,3,4,2,2,3] B=A[:] A.sort(key=lambda x:B.count(x)) print(A)Confirmado por esta línea en la documentación de python
Detalle de implementación de CPython: mientras se ordena una lista, el efecto de intentar mutar, o incluso inspeccionar, la lista no está definido. La implementación en C de Python hace que la lista parezca vacía durante el tiempo que dura y genera ValueError si puede detectar que la lista se ha mutado durante una ordenación.
Creo que es porque A.sort está modificando la lista que se encuentra debajo durante la computación. sorted() no modifica la lista y, por lo tanto, devuelve un resultado correcto.