¿Se garantiza que la función sorted () de Python sea estable?

97

La documentación no garantiza eso. ¿Hay algún otro lugar donde esté documentado?

Supongo que podría ser estable ya que se garantiza que el método de ordenación en las listas sea ​​estable (Notas 9º punto: "A partir de Python 2.3, se garantiza que el método de ordenación () es estable"), y ordenado es funcionalmente similar. Sin embargo, no puedo encontrar ninguna fuente definitiva que lo diga.

Propósito: necesito ordenar en función de una clave principal y también una clave secundaria en los casos en que la clave principal es igual en ambos registros. Si se garantiza que sorted () sea estable, puedo ordenar la clave secundaria, luego ordenar la clave principal y obtener el resultado que necesito.

PD: Para evitar confusiones, estoy usando estable en el sentido de "un tipo es estable si garantiza no cambiar el orden relativo de los elementos que se comparan iguales".

sundar - Reincorporar a Monica
fuente

Respuestas:

128

Sí, la intención del manual es garantizar que sortedsea ​​estable y que utilice exactamente el mismo algoritmo que el sortmétodo. Me doy cuenta de que los documentos no son 100% claros sobre esta identidad; ¡Los parches doc siempre se aceptan con gusto!

Alex Martelli
fuente
2
Descubrí que si estoy ordenando tuplas o listas, siempre que las claves de ordenación "primarias" son iguales, termina ordenando por la clave "secundaria". Por ejemplo, sorted([(1, 2), (1, 1)])devuelve en [(1, 1), (1, 2)]lugar de devolver la entrada original en la misma secuencia / orden. ¿No debería la garantía de estabilidad significar que debería devolver la [(1, 2), (1, 1)]entrada original ? En ese caso, debe ser explícito y decirsorted([(1, 2), (1, 1)], key=lambda t: t[0])
code_dredd
10
¿No es esto lo que se espera en este caso? Python va a comparar tuplas a través de todos los elementos por defecto, no solo el primero "primario". Si solo desea ordenar por el primer elemento, puede pasar el keyparámetro explícitamente.
Matias Grioni
2
@code_dredd este es el comportamiento esperado. El objetivo de la ordenación estable es ordenar mediante una "clave de ordenación", pero dos elementos diferentes que tienen la misma clave de ordenación estarán en el mismo orden. La clave de clasificación predeterminada para una tupla son todos los elementos de la tupla.
guyarad
28

Son estables .

Por cierto: a veces puede ignorar si la ordenación y la ordenación son estables, combinando una ordenación de múltiples pasadas en una de una sola pasada.

Por ejemplo, si desea ordenar los objetos en función de sus last_name, first_nameatributos, puede hacerlo en una sola pasada:

sorted_list= sorted(
    your_sequence_of_items,
    key= lambda item: (item.last_name, item.first_name))

aprovechando la comparación de tuplas.

Esta respuesta, tal como está, cubre la pregunta original. Para más preguntas relacionadas con la clasificación, está el Procedimiento de clasificación de Python .

tzot
fuente
5
Esto puede tener un efecto no deseado si desea invertir el orden. Por ejemplo, al ordenar productos, es posible que desee ordenar primero por calificación (orden ascendente) y luego por precio (también ascendente). Si invierte esto, desea ordenar por calificación en orden descendente pero por precio en orden ascendente. Esto no funciona con esta solución.
Remco Wendt
2
@RemcoWendt: no había ningún requisito para lo que describe. En cualquier caso, considere key= lambda item: (-item.rating, item.price)o proporcione un en cmplugar de un keyargumento. Sin embargo, todavía no estoy seguro del propósito de tu comentario.
tzot
1
De hecho, no era un requisito, pero quería señalar esta sutil diferencia cuando otras personas leen esto y eligen entre su solución o usar la función de clasificación estable de Python.
Remco Wendt
Veo. En otras palabras, la clasificación por pares es más clara y, por tanto, preferible, a menos que le importe el rendimiento. Me imagino que dos tipos estables son algo más rápidos que uno por pares, aunque la diferencia puede ser insignificante -?
Sergey Orshanskiy
8
@tzot Quiero mencionar, siempre existen tales requisitos para una clasificación estable. Por ejemplo, tengo una lista de tuplas (tasa, comentario), los comentarios se guardan en el orden en que se hicieron y quiero ordenar por tasa y mantener el orden de tiempo, sin embargo, no guardé el marca de tiempo en la lista. Para decirlo brevemente, solo quiero ordenar la lista por tasa y mantener el comentario en el mismo orden.
wsysuper
3

Mientras tanto, la documentación cambió ( compromiso relevante ) y la documentación actual sortedlo garantiza explícitamente:

Se sorted()garantiza que la función incorporada será estable. Una clasificación es estable si garantiza que no se cambiará el orden relativo de los elementos que se comparan iguales; esto es útil para clasificar en varias pasadas (por ejemplo, ordenar por departamento y luego por grado salarial).

Esta parte de la documentación se agregó a Python 2.7 y Python 3.4 (+) por lo que cualquier implementación compatible de esa versión de lenguaje debería tener un archivo sorted.

Tenga en cuenta que para CPython se list.sortha mantenido estable desde Python 2.3

  • Tim Peters reescribió su list.sort()implementación: esta es una "clase estable" (las entradas iguales aparecen en el mismo orden en la salida) y más rápida que antes.

No estoy 100% seguro sorted, hoy en día es un uso simple list.sort, pero no he revisado el historial para eso. Pero es probable que se use "siempre" list.sort.

MSeifert
fuente
0

Los documentos de "Novedades" para Python 2.4 señalan efectivamente que sorted () primero crea una lista, luego llama a sort () en ella, proporcionándote la garantía que necesitas aunque no en los documentos "oficiales". También puede verificar la fuente, si está realmente preocupado.

Peter Hansen
fuente
1
¿Podría señalar dónde dice eso? Dice sorted () "funciona como list.sort () en el lugar" y "se ordena una copia recién formada", pero no veo que diga que utiliza internamente sort ().
sundar - Reincorporación a Monica
La "copia" que se forma es una lista (eso es lo que obtiene como valor de retorno), y .sort () se llama en esa lista antes de regresar. QED. No, no es una prueba irrefutable, pero hasta que Python tenga un estándar oficial, no lo obtendrá.
Peter Hansen
0

El documento de Python 3.6 sobre clasificación ahora establece que

Se garantiza que las clases sean estables

Además, en ese documento, hay un enlace al Timsort estable , que establece que

Timsort ha sido el algoritmo de clasificación estándar de Python desde la versión 2.3

Wolfgang Kuehn
fuente