Como classificar uma lista de cadeias numericamente?

128

Eu sei que isso parece trivial, mas eu não percebi que a sort()função do Python era estranha. Eu tenho uma lista de "números" que estão realmente na forma de seqüência de caracteres, então primeiro os converto em ints e, em seguida, tente uma classificação.

list1=["1","10","3","22","23","4","2","200"]
for item in list1:
    item=int(item)

list1.sort()
print list1

Dá-me:

['1', '10', '2', '200', '22', '23', '3', '4']

O que eu quero é

['1','2','3','4','10','22','23','200']

Procurei alguns dos algoritmos associados à classificação de conjuntos numéricos, mas os que encontrei envolvem a classificação de conjuntos alfanuméricos.

Eu sei que este é provavelmente um problema óbvio, mas o google e meu livro não oferecem nada mais ou menos útil do que a .sort()função.

Brian
fonte
9
Observe que o loop for não faz o que eu suspeito que você pensa que faz.
deinst
1
Em nenhum momento você atualizou list1. O que fez você pensar que listestava sendo atualizado?
S.Lott
O problema semelhante ocorre quando list1 = ['1', '1,10', '1,11', '1,1', '1,2'] é fornecido como entrada. Em vez de obter a saída como ['1', '1.1', '1.2', '1.10', '1.11'], estou recebendo ['1', '1.1', '1.10', '1.11', '1.2' ]
sathish
2
em python 3, você pode querer usarsorted(mylist)
Akin Hwan

Respostas:

191

Você não converteu suas strings em ints. Ou melhor, você fez, mas não fez nada com os resultados. O que você quer é:

list1 = ["1","10","3","22","23","4","2","200"]
list1 = [int(x) for x in list1]
list1.sort()

Se, por algum motivo, você precisar manter seqüências de caracteres em vez de ints (geralmente uma má ideia, mas talvez seja necessário preservar zeros à esquerda ou algo assim), use uma função de tecla . sortusa um parâmetro nomeado key, que é uma função que é chamada em cada elemento antes de ser comparada. Os valores de retorno da função-chave são comparados em vez de comparar diretamente os elementos da lista:

list1 = ["1","10","3","22","23","4","2","200"]
# call int(x) on each element before comparing it
list1.sort(key=int)
Seamus Campbell
fonte
8
quando eu tento key = int em 2.7, recebo None
KI4JGT 28/01
1
Isso funciona se o elemento da lista for armazenado como "número inteiro", como deve ser tratado no caso de valores flutuantes? Por exemplo, list1 = [1, 1.10, 1.11, 1.1, 1.2]
sathish
1
@ KI4JGT, o método de classificação modifica a lista e retorna Nenhum. Então, em vez de list1 = list1.sort(key=int), use just list1.sort(key=int)e list1 já estará classificado.
Josias Yoder
1
@ KI4JGT .Sort () é um operador in lugar, ele retorna None, ele classifica a lista, você pode querer usar classificadas ()
sherpya
39

Você poderia passar uma função para o keyparâmetro para o .sortmétodo . Com isso, o sistema classificará pela tecla (x) em vez de x.

list1.sort(key=int)

BTW, para converter a lista em números permanentemente, use a mapfunção

list1 = list(map(int, list1))   # you don't need to call list() in Python 2.x

ou compreensão da lista

list1 = [int(x) for x in list1]
kennytm
fonte
21

Caso você queira usar a sorted()função:sorted(list1, key=int)

Retorna uma nova lista classificada.

syam
fonte
1
Funciona com conjuntos também!
MT
12

O tipo de Python não é estranho. É apenas que este código:

for item in list1:
   item=int(item)

não está fazendo o que você pensa que é - itemnão é substituído novamente na lista, é simplesmente jogado fora.

De qualquer forma, a solução correta é usar key=intcomo outras pessoas lhe mostraram.

Daniel Roseman
fonte
12

Você também pode usar:

import re

def sort_human(l):
    convert = lambda text: float(text) if text.isdigit() else text
    alphanum = lambda key: [convert(c) for c in re.split('([-+]?[0-9]*\.?[0-9]*)', key)]
    l.sort(key=alphanum)
    return l

Isso é muito semelhante a outras coisas que você pode encontrar na internet, mas também funciona para alfanuméricos como [abc0.1, abc0.2, ...].

Julian
fonte
8

A resposta de Seamus Campbell não funciona em python2.x.
list1 = sorted(list1, key=lambda e: int(e))usar a lambdafunção funciona bem.

Marx Wolf
fonte
8

Abordei o mesmo problema ontem e encontrei um módulo chamado [natsort] [1], que resolve o seu problema. Usar:

from natsort import natsorted # pip install natsort

# Example list of strings
a = ['1', '10', '2', '3', '11']

[In]  sorted(a)
[Out] ['1', '10', '11', '2', '3']

[In]  natsorted(a)
[Out] ['1', '2', '3', '10', '11']

# Your array may contain strings
[In]  natsorted(['string11', 'string3', 'string1', 'string10', 'string100'])
[Out] ['string1', 'string3', 'string10', 'string11', 'string100']

Também funciona para dicionários como equivalente a sorted. [1]: https://pypi.org/project/natsort/

rfaenger
fonte
3

Tente isso, ele classificará a lista no local em ordem decrescente (não é necessário especificar uma chave nesse caso):

Processo

listB = [24, 13, -15, -36, 8, 22, 48, 25, 46, -9]
listC = sorted(listB, reverse=True) # listB remains untouched
print listC

resultado:

 [48, 46, 25, 24, 22, 13, 8, -9, -15, -36]
Mavia
fonte
0

A solução mais recente está certa. Você está lendo as soluções como uma sequência; nesse caso, a ordem é 1, depois 100, depois 104, seguida por 2 e 21, 2001001010, 3 e assim por diante.

Você deve CAST sua entrada como int:

strings ordenadas:

stringList = (1, 10, 2, 21, 3)

ints classificados:

intList = (1, 2, 3, 10, 21)

Para transmitir, basta colocar a stringList dentro de int (blahblah).

Novamente:

stringList = (1, 10, 2, 21, 3)

newList = int (stringList)

print newList

=> returns (1, 2, 3, 10, 21) 
clint
fonte
1
TypeError: int (argumento) deve ser uma string ou um número, não 'tuple'
Cees Timmerman
Além disso, as strings em sua stringList devem ter aspas.
214156 Teepeemm
2
Essa é uma previsão infernal a ser feita: "a solução mais recente está correta";)
GreenAsJade 29/02/16
0

Se você quiser usar seqüências de caracteres dos números, melhor tomar outra lista, como mostrado no meu código, funcionará bem.

list1=["1","10","3","22","23","4","2","200"]

k=[]    
for item in list1:    
    k.append(int(item))

k.sort()
print(k)
# [1, 2, 3, 4, 10, 22, 23, 200]
Shaystorm
fonte
0

Maneira simples de classificar uma lista numérica

numlists = ["5","50","7","51","87","97","53"]
results = list(map(int, numlists))
results.sort(reverse=False)
print(results)
sayalok
fonte
-1

O verdadeiro problema é que esse tipo classifica as coisas alfanumericamente. Portanto, se você tiver uma lista ['1', '2', '10', '19'] e executar a ordenação, obterá ['1', '10'. '19', '2']. ou seja, 10 vem antes de 2 porque olha para o primeiro caractere e classifica a partir dele. Parece que a maioria dos métodos em python retorna as coisas nessa ordem. Por exemplo, se você tiver um diretório chamado abc com os arquivos rotulados como 1.jpg, 2.jpg etc, diga até 15.jpg e faça file_list = os.listdir (abc), a file_list não será solicitada conforme o esperado, mas sim como file_list = ['1.jpg', '11 .jpg '---' 15.jpg ',' 2.jpg]. Se a ordem na qual os arquivos são processados ​​for importante (presumivelmente é por isso que você os nomeou numericamente), a ordem não será a que você pensa que será. Você pode evitar isso usando o preenchimento "zeros". Por exemplo, se você tiver uma lista alist = ['01', '03', '05', '10', '02', '04', '06] e executar a classificação nela, obterá a ordem desejada. alist = ['01', '02' etc] porque o primeiro caractere é 0, que vem antes de 1. A quantidade de preenchimento de zeros que você precisa é determinada pelo maior valor da lista.Por exemplo, se o maior for digitado entre 100 e 1000, você precisa preencher dígitos únicos como 001, 002-010,011--100, 101 etc.

Gerry P
fonte
-5
scores = ['91','89','87','86','85']
scores.sort()
print (scores)

Isso funcionou para mim usando o python versão 3, embora não na versão 2.

Kamal Reddy
fonte
3
Tente classificar com '11 e '100' lá, é quando as coisas ficam interessantes.
Penz