Powiedzmy, że mam dwie listy:
list1 = [3, 2, 4, 1, 1]
list2 = ['three', 'two', 'four', 'one', 'one2']
Jeśli uruchomię list1.sort()
, posortuje to, [1,1,2,3,4]
ale czy istnieje również sposób na list2
zsynchronizowanie (więc mogę powiedzieć, że element 4
należy 'three'
)? Tak więc oczekiwany wynik to:
list1 = [1, 1, 2, 3, 4]
list2 = ['one', 'one2', 'two', 'three', 'four']
Mój problem polega na tym, że mam dość złożony program, który działa dobrze z listami, ale muszę zacząć odwoływać się do niektórych danych. Wiem, że jest to idealna sytuacja dla słowników, ale staram się unikać słowników podczas przetwarzania, ponieważ muszę sortować kluczowe wartości (jeśli muszę używać słowników, wiem, jak ich używać).
Zasadniczo charakter tego programu polega na tym, że dane są w losowej kolejności (jak powyżej), muszę je posortować, przetworzyć, a następnie wysłać wyniki (kolejność nie ma znaczenia, ale użytkownicy muszą wiedzieć, do którego wyniku należy klucz). Myślałem o umieszczeniu go najpierw w słowniku, a potem posortowaniu listy, ale nie miałbym możliwości rozróżnienia pozycji o tej samej wartości, gdyby nie zachowano kolejności (może to mieć wpływ na komunikowanie wyników użytkownikom). Więc idealnie, gdy już otrzymam listy, wolałbym wymyślić sposób posortowania obu list razem. czy to możliwe?
Odpowiedzi:
Klasycznym podejściem do tego problemu jest użycie idiomu „dekoruj, sortuj, dekoruj”, co jest szczególnie proste dzięki wbudowanej
zip
funkcji Pythona :To oczywiście nie są już listy, ale jeśli ma to znaczenie, można to łatwo naprawić:
Warto zauważyć, że powyższe może poświęcać szybkość na rzecz zwięzłości; wersja lokalna, która zajmuje 3 wiersze, jest odrobinę szybsza na moim komputerze w przypadku małych list:
Z drugiej strony, w przypadku większych list, wersja jednowierszowa mogłaby być szybsza:
Jak wskazuje Quantum7, sugestia JSF jest jeszcze trochę szybsza, ale prawdopodobnie będzie tylko trochę szybsza, ponieważ Python używa wewnętrznie tego samego idiomu DSU dla wszystkich typów opartych na kluczach. To się dzieje trochę bliżej gołego metalu. (To pokazuje, jak dobrze zoptymalizowane
zip
są procedury!)Myślę, że
zip
podejście oparte na zasadzie jest bardziej elastyczne i jest trochę bardziej czytelne, więc wolę je.źródło
*
operator rozpakowuje argumenty ,zip(*x)
ma interesującą własność, że jest swoją własną odwrotnością:l = [(1, 2), (3, 4)]; list(zip(*zip(*l))) == l
zwracaTrue
. W rzeczywistości jest operatorem transpozycji.zip()
sam w sobie jest tym samym operatorem, ale zakłada, że ręcznie rozpakowałeś sekwencję wejściową.Indeksy można sortować, używając wartości jako kluczy:
Aby uzyskać posortowane listy z posortowanymi indeksami:
W twoim przypadku nie powinieneś mieć
list1
,list2
a raczej jedną listę par:Jest łatwy do stworzenia; w Pythonie łatwo jest sortować:
Sortuj tylko według pierwszej wartości:
źródło
list()
obejść,map()
jeśli chcesz użyć tego kodu w Pythonie 3.sorted_list1 = list(map(list1.__getitem__, indexes))
możnasorted_list1 = [list1[i] for i in indexes]
.Korzystałem z odpowiedzi udzielonej przez senderle przez długi czas, dopóki nie odkryłem
np.argsort
. Oto jak to działa.Uważam, że to rozwiązanie jest bardziej intuicyjne i działa naprawdę dobrze. Wydajność:
Chociaż
np.argsort
nie jest najszybszy, jest dla mnie łatwiejszy w użyciu.źródło
TypeError: only integer arrays with one element can be converted to an index
Podczas uruchamiania Twojego przykładu pojawia się błąd: (Python 2.7.6, numpy 1.8.2). Aby to naprawić, lista1 i lista2 muszą być zadeklarowane jako tablice numpy.np.argsort
nie próbuj nawracać sięnp.array
wewnętrznie.Transformacja Schwartza . Wbudowane sortowanie w Pythonie jest stabilne, więc oba
1
nie powodują problemu.źródło
Co powiesz na:
źródło
Aby to osiągnąć, możesz użyć funkcji
zip()
isort()
:Mam nadzieję że to pomoże
źródło
Możesz użyć argumentu klucza w metodzie sort (), chyba że masz dwie takie same wartości w liście2.
Kod jest podany poniżej:
Sortuje listę2 według odpowiednich wartości z listy1, ale upewnij się, że podczas korzystania z niej żadne dwie wartości z listy2 nie są równe, ponieważ funkcja list.index () podaje pierwszą wartość
źródło
Jednym ze sposobów jest śledzenie, dokąd przechodzi każdy indeks, poprzez sortowanie tożsamości [0,1,2, .. n]
Działa to dla dowolnej liczby list.
Następnie przenieś każdy element na jego miejsce. Najlepiej używać złączy.
Zauważ, że mogliśmy iterować listy bez ich sortowania:
źródło
Jeśli używasz numpy, możesz użyć,
np.argsort
aby pobrać posortowane indeksy i zastosować je do listy. Działa to dla dowolnej liczby list, które chcesz posortować.źródło
rozwiązanie algorytmiczne:
Wyjścia:
->
Prędkość wyjściowa:0.2s
źródło
Inne podejście do zachowania porządku listy ciągów podczas sortowania według innej listy jest następujące:
wynik
źródło
Chciałbym rozszerzyć odpowiedź otwartego jfs , która świetnie się sprawdziła w moim problemie: sortowanie dwóch list według trzeciej, ozdobionej listy :
Naszą dekorowaną listę możemy stworzyć w dowolny sposób, ale w tym przypadku stworzymy ją z elementów jednej z dwóch oryginalnych list, które chcemy posortować:
Teraz możemy zastosować rozwiązanie jfs, aby posortować nasze dwie listy według trzeciej
Edycja: Hej chłopaki, napisałem o tym blokowy post, sprawdź to, jeśli masz na to ochotę :) 🐍🐍🐍
źródło
źródło