Jak numerycznie posortować listę ciągów?

128

Wiem, że brzmi to banalnie, ale nie zdawałem sobie sprawy, że sort()funkcja Pythona jest dziwna. Mam listę „liczb”, które są w rzeczywistości w postaci ciągów, więc najpierw konwertuję je na liczby całkowite, a następnie próbuję posortować.

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

list1.sort()
print list1

Daje mi:

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

Ja chcę

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

Rozejrzałem się za niektórymi algorytmami związanymi z sortowaniem zestawów liczbowych, ale te, które znalazłem, obejmują sortowanie zestawów alfanumerycznych.

Wiem, że jest to prawdopodobnie nie do pomyślenia problem, ale Google i mój podręcznik nie oferują nic bardziej lub mniej użytecznego niż ta .sort()funkcja.

Brian
źródło
9
Zauważ, że twoja pętla for nie robi tego, co podejrzewam, że myślisz, że robi.
deinst
1
W żadnym momencie nie aktualizowałeś list1. Co sprawiło, że myślisz, że listjest aktualizowane?
S.Lott
Podobny problem pojawia się, gdy lista1 = ['1', '1,10', '1,11', '1,1', '1,2'] jest podana jako dane wejściowe. Zamiast otrzymywać dane wyjściowe jako ['1', '1,1', '1,2', '1,10', '1,11'], otrzymuję ['1', '1.1', '1,10', '1.11', '1.2' ]
satish
2
w Pythonie 3 możesz chcieć użyćsorted(mylist)
Akin Hwan

Odpowiedzi:

191

W rzeczywistości nie przekonwertowałeś swoich stringów na ints. A raczej zrobiłeś, ale potem nic nie zrobiłeś z wynikami. Chcesz:

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

Jeśli z jakiegoś powodu chcesz zachować ciągi znaków zamiast int (zwykle jest to zły pomysł, ale może musisz zachować zera wiodące lub coś w tym rodzaju), możesz użyć funkcji klucza . sortprzyjmuje nazwany parametr, keyczyli funkcję wywoływaną na każdym elemencie przed porównaniem. Wartości zwracane przez funkcję klucza są porównywane zamiast bezpośrednio porównywać elementy listy:

list1 = ["1","10","3","22","23","4","2","200"]
# call int(x) on each element before comparing it
list1.sort(key=int)
Seamus Campbell
źródło
8
kiedy próbuję key = int w 2.7, otrzymuję None
KI4JGT
1
Działa to, jeśli element listy jest przechowywany jako „liczba całkowita”, jak należy postępować w przypadku wartości zmiennoprzecinkowych? Np. Lista1 = [1, 1.10, 1.11, 1.1, 1.2]
sathish
1
@ KI4JGT metoda sortowania modyfikuje listę i zwraca None. Więc zamiast tego list1 = list1.sort(key=int)użyj just, list1.sort(key=int)a lista1 będzie już posortowana.
Josiah Yoder
1
@ KI4JGT .sort () jest operatorem miejscowym, zwraca None, sortuje listę, możesz użyć sortowania ()
sherpya
39

Można przekazać do funkcji keyparametr do tej .sortmetody . Dzięki temu system sortuje według klucza (x) zamiast x.

list1.sort(key=int)

BTW, przekonwertować do listy liczb całkowitych na stałe, należy w mapfunkcji

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

lub rozumienie listy

list1 = [int(x) for x in list1]
kennytm
źródło
21

Jeśli chcesz użyć sorted()funkcji:sorted(list1, key=int)

Zwraca nową posortowaną listę.

syam
źródło
1
Działa też z zestawami!
MT
12

Rodzaj Pythona nie jest dziwny. Po prostu ten kod:

for item in list1:
   item=int(item)

nie robi tego, co myślisz, że jest - itemnie jest ponownie umieszczany na liście, jest po prostu wyrzucany.

Tak czy inaczej, właściwym rozwiązaniem jest używanie tego, key=intco inni ci pokazali.

Daniel Roseman
źródło
12

Możesz także użyć:

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

Jest to bardzo podobne do innych rzeczy, które można znaleźć w Internecie, ale działa również w przypadku znaków alfanumerycznych, takich jak [abc0.1, abc0.2, ...].

juliański
źródło
8

Odpowiedź Seamusa Campbella nie działa na python2.x.
list1 = sorted(list1, key=lambda e: int(e))używanie lambdafunkcji działa dobrze.

Marx Wolf
źródło
8

Wczoraj zbliżyłem się do tego samego problemu i znalazłem moduł o nazwie [natsort] [1], który rozwiązuje twój problem. Posługiwać się:

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']

Działa również w przypadku słowników jako odpowiednik sorted. [1]: https://pypi.org/project/natsort/

rfaenger
źródło
3

Spróbuj tego, posortuje listę lokalnie w porządku malejącym (w tym przypadku nie ma potrzeby określania klucza):

Proces

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

wynik:

 [48, 46, 25, 24, 22, 13, 8, -9, -15, -36]
Mavia
źródło
0

Najnowsze rozwiązanie jest słuszne. Odczytujesz rozwiązania jako ciąg, w którym to przypadku kolejność to 1, potem 100, potem 104, potem 2, potem 21, potem 2001001010, 3 i tak dalej.

Zamiast tego musisz przelać swoje dane wejściowe jako int:

posortowane ciągi:

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

posortowane int:

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

Aby rzucić, po prostu umieść stringList wewnątrz int (blahblah).

Jeszcze raz:

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

newList = int (stringList)

print newList

=> returns (1, 2, 3, 10, 21) 
Clint
źródło
1
TypeError: argument int () musi być łańcuchem lub liczbą, a nie „krotką”
Cees Timmerman
Również łańcuchy w stringList powinny mieć cudzysłowy.
Teepeemm
2
To piekielna prognoza: „najnowsze rozwiązanie jest słuszne”;)
GreenAsJade
0

Jeśli chcesz użyć ciągów liczb, lepiej weź inną listę, jak pokazano w moim kodzie, będzie działać dobrze.

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
źródło
0

Prosty sposób sortowania listy numerycznej

numlists = ["5","50","7","51","87","97","53"]
results = list(map(int, numlists))
results.sort(reverse=False)
print(results)
sayalok
źródło
-1

prawdziwym problemem jest to, że sortowanie rzeczy jest alfanumeryczne. Więc jeśli masz listę [„1”, „2”, „10”, „19”] i uruchomisz sortowanie, otrzymasz [„1”, „10”. „19”, „2”]. tj. 10 jest przed 2, ponieważ patrzy na pierwszy znak i sortuje zaczynając od niego. Wygląda na to, że większość metod w Pythonie zwraca rzeczy w tej kolejności. Na przykład, jeśli masz katalog o nazwie abc z plikami oznaczonymi jako 1.jpg, 2.jpg itp., Powiedz do 15.jpg i zrobisz plik_list = os.listdir (abc), lista_plików nie jest uporządkowana zgodnie z oczekiwaniami, ale raczej file_list = ['1.jpg', '11 .jpg '---' 15.jpg ',' 2.jpg]. Jeśli kolejność przetwarzania plików jest ważna (prawdopodobnie dlatego nadałeś im nazwy numeryczne), kolejność nie jest taka, jak myślisz, że będzie. Możesz tego uniknąć, używając dopełnienia zerami. Na przykład, jeśli masz listę alist = ['01', '03', '05', '10', '02', '04', '06] i uruchomisz na niej sortowanie, otrzymasz żądaną kolejność. alist = ['01', '02' itd.], ponieważ pierwszy znak to 0, który występuje przed 1. Ilość potrzebnych wypełnień zerami jest określana na podstawie największej wartości na liście. Na przykład, jeśli największa to powiedzmy od 100 do 1000 musisz wpisać pojedyncze cyfry jako 001, 002 --- 010,011-100, 101 itd.

Gerry P
źródło
-5
scores = ['91','89','87','86','85']
scores.sort()
print (scores)

To zadziałało dla mnie przy użyciu Pythona w wersji 3, chociaż nie w wersji 2.

Kamal Reddy
źródło
3
Spróbuj posortować je według „11” i „100”, wtedy robi się ciekawie.
Penz