A função Sorted () do python tem garantia de estabilidade?

95

A documentação não garante isso. Existe algum outro local onde esteja documentado?

Eu estou supondo que pode ser estável, já que o método de classificação nas listas é garantidamente estável (Notas 9º ponto: "Começando com Python 2.3, o método sort () é garantido como estável") e classificado é funcionalmente semelhante. No entanto, não consigo encontrar nenhuma fonte definitiva que diga isso.

Objetivo: preciso classificar com base em uma chave primária e também em uma chave secundária nos casos em que a chave primária é igual em ambos os registros. Se ordenado () for estável, posso classificar a chave secundária e, em seguida, classificar a chave primária e obter o resultado de que preciso.

PS: Para evitar qualquer confusão, estou usando estável no sentido de "uma classificação é estável se garantir não alterar a ordem relativa dos elementos que comparam iguais".

sundar - Reintegrar Monica
fonte

Respostas:

126

Sim, a intenção do manual é garantir que sortedseja estável e que use exatamente o mesmo algoritmo do sortmétodo. Sei que os documentos não são 100% claros sobre essa identidade; patches de doc são sempre aceitos com alegria!

Alex Martelli
fonte
2
Descobri que, se estou classificando tuplas ou listas, sempre que as chaves de classificação "primárias" são iguais, acaba classificando pela chave "secundária". Por exemplo, sorted([(1, 2), (1, 1)])retorna em [(1, 1), (1, 2)]vez de retornar a entrada original na mesma sequência / ordem. A garantia de estabilidade não deveria significar que ele deveria retornar a [(1, 2), (1, 1)]entrada original ? Nesse caso, você deve ser explícito e dizersorted([(1, 2), (1, 1)], key=lambda t: t[0])
code_dredd 01 de
10
Não é isso que se espera neste caso? O Python vai comparar tuplas por meio de todos os elementos por padrão, não apenas o primeiro "primário". Se você deseja ordenar apenas pelo primeiro elemento, pode passar o keyparâmetro explicitamente.
Matias Grioni
2
@code_dredd este é o comportamento esperado. O ponto da classificação estável é classificar usando uma "chave de classificação", mas dois elementos diferentes que têm a mesma chave de classificação estarão na mesma ordem. A chave de classificação padrão para uma tupla são todos os elementos da tupla.
guyarad
27

Eles são estáveis .

A propósito: às vezes você pode ignorar saber se a classificação e a classificação são estáveis, combinando uma classificação de várias passagens em uma de passagem única.

Por exemplo, se você quiser classificar os objetos com base em suas last_name, first_nameatributos, você pode fazê-lo em uma passagem:

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

aproveitando a comparação de tupla.

Esta resposta, tal como está, cobre a pergunta original. Para outras questões relacionadas à classificação, há o Python Sorting How-To .

tzot
fonte
4
Isso pode ter um efeito indesejado se você quiser reverter a classificação. Por exemplo, ao classificar os produtos, você pode querer primeiro classificar pela classificação (ordem crescente) e depois pelo preço (também crescente). Se você inverter isso, deseja classificar por classificação em ordem decrescente, mas por preço em ordem crescente. Isso não funciona com esta solução.
Remco Wendt
2
@RemcoWendt: não havia nenhum requisito para o que você descreve. Em qualquer caso, considere key= lambda item: (-item.rating, item.price)ou forneça um em cmpvez de um keyargumento. Ainda não tenho certeza sobre o propósito do seu comentário, no entanto.
tzot
1
Na verdade, não era um requisito, mas queria apontar essa diferença sutil quando outras pessoas lêem isso e fazem uma escolha entre sua solução ou usar o recurso de classificação estável do Python.
Remco Wendt
Entendo. Em outras palavras, a classificação por pares é mais clara e, portanto, preferível, a menos que você se preocupe com o desempenho. Eu imagino que duas classificações estáveis ​​são um pouco mais rápidas do que uma classificação por pares, embora a diferença possa ser insignificante -?
osa
8
@tzot, quero mencionar, sempre existem esses requisitos para a classificação estável. Por exemplo, eu tenho uma lista de tupla (taxa, comentário), os comentários são salvos na ordem de quando foram feitos, e eu quero classificar pela taxa e manter a ordem do tempo, no entanto, não salvei o timestamp na lista. Para resumir, quero apenas classificar a lista por taxa e manter o comentário na mesma ordem.
wsysuper
3

A documentação mudou entretanto ( commit relevante ) e a documentação atual sortedgarante explicitamente:

A sorted()função integrada tem garantia de estabilidade. Uma classificação é estável se garante não alterar a ordem relativa dos elementos que são comparados iguais - isso é útil para classificar em várias passagens (por exemplo, classificar por departamento e depois por nível de salário).

Esta parte da documentação foi adicionada ao Python 2.7 e Python 3.4 (+), portanto, qualquer implementação compatível dessa versão da linguagem deve ter uma versão estável sorted.

Observe que, para CPython, o list.sorté estável desde Python 2.3

  • Tim Peters reescreveu sua list.sort()implementação - esta é uma "classificação estável" (entradas iguais aparecem na mesma ordem na saída) e mais rápido do que antes.

Não tenho 100% de certeza sorted, hoje em dia é simples de usar list.sort, mas não chequei o histórico disso. Mas é provável que "sempre" tenha sido usado list.sort.

MSeifert
fonte
0

A documentação "O que há de novo" para Python 2.4 efetivamente mostra que o Sort () primeiro cria uma lista, então chama sort () nela, fornecendo a você a garantia de que você precisa, embora não esteja na documentação "oficial". Você também pode verificar a fonte, se estiver realmente preocupado.

Peter Hansen
fonte
1
Você poderia apontar onde diz isso? Ele diz Sorted () "funciona como list.sort () no local" e "uma cópia recém-formada é classificada", mas não vejo que diga que usa sort () internamente.
sundar - Reintegrar Monica em
A "cópia" formada é uma lista (é o que você obtém como valor de retorno) e .sort () é chamado nessa lista antes de retornar. QED. Não, não é uma prova inatacável, mas até que o Python tenha um padrão oficial, você não terá isso.
Peter Hansen
0

O documento do Python 3.6 sobre classificação agora afirma que

As classificações têm garantia de estabilidade

Além disso, naquele documento, há um link para o Timsort estável , que afirma que

Timsort é o algoritmo de classificação padrão do Python desde a versão 2.3

Wolfgang Kuehn
fonte