Czy istnieje pythonowy sposób sprawdzenia, czy lista jest już posortowana w ASC
lubDESC
listtimestamps = [1, 2, 3, 5, 6, 7]
coś takiego isttimestamps.isSorted()
wraca True
lub False
.
Chcę wprowadzić listę znaczników czasu dla niektórych wiadomości i sprawdzić, czy transakcje pojawiły się we właściwej kolejności.
key
funkcję do użycia.key=lambda x, y: x < y
to dobre ustawienie domyślne.def isSorted(x, key = lambda x: x): return all([key(x[i]) <= key(x[i + 1]) for i in xrange(len(x) - 1)])
operator.le
powinno być szybsze niż lambdal = [1, 2, 3, 4, 1, 6, 7, 8, 7] all(l[i] <= l[i+1] for i in xrange(len(l)-1))
drukuj jako wynik:True
xrange
, po prostu użyjrange
. Otrzymuję,NameError: name 'xrange' is not defined
kiedy uruchamiam ten kod. Przełączyłem go na zwykłe używanierange
zamiastxrange
i to działa dobrze. Zobacz: stackoverflow.com/questions/15014310/…Po prostu użyłbym
chyba że jest to bardzo duża lista, w takim przypadku możesz chcieć utworzyć funkcję niestandardową.
jeśli zamierzasz go po prostu posortować, jeśli nie jest posortowany, zapomnij o sprawdzeniu i posortuj go.
i nie myśl o tym za dużo.
jeśli chcesz mieć funkcję niestandardową, możesz zrobić coś takiego
Będzie to O (n), jeśli lista jest już posortowana (i O (n) w
for
pętli!), Więc chyba że spodziewasz się, że nie będzie posortowana (i dość losowa) przez większość czasu, zrobiłbym to, ponownie, po prostu posortuj listę.źródło
Ta forma iteratora jest o 10–15% szybsza niż przy indeksowaniu liczb całkowitych:
źródło
izip
iislice
z itertools, aby przyspieszyć.Pięknym sposobem na zaimplementowanie tego jest użycie
imap
funkcji zitertools
:Ta implementacja jest szybka i działa na dowolnych iterowalnych.
źródło
is_sorted(iter([1,2,3,2,5,8]))
lub równoważnym generatorze. Musisz użyć niezależnego iteratoratail
, spróbujitertools.tee
.iter(x) is x
dla iteratorówitertools.imap
zmieniono nazwę na[__builtins__.]map
.Przeprowadziłem test porównawczy
i. Te testy porównawcze zostały uruchomione na 13-calowym MacBooku Pro 2010 (Core2 Duo 2,66 GHz, 4 GB 1067 MHz DDR3 RAM, Mac OS X 10.6.5).sorted(lst, reverse=True) == lst
byłem najszybszy w przypadku długich list iall(l[i] >= l[i+1] for i in xrange(len(l)-1))
najszybszy w przypadku krótkich listAKTUALIZACJA: Poprawiłem skrypt, abyś mógł uruchomić go bezpośrednio w swoim własnym systemie. Poprzednia wersja zawierała błędy. Dodałem również posortowane i nieposortowane dane wejściowe.all(l[i] >= l[i+1] for i in xrange(len(l)-1))
sorted(l, reverse=True) == l
all(l[i] >= l[i+1] for i in xrange(len(l)-1))
all(l[i] >= l[i+1] for i in xrange(len(l)-1))
Więc w większości przypadków jest wyraźny zwycięzca.AKTUALIZACJA: odpowiedzi aaronsterlinga (# 6 i # 7) są w rzeczywistości najszybsze we wszystkich przypadkach. # 7 jest najszybszy, ponieważ nie ma warstwy pośredniej do wyszukiwania klucza.
źródło
enumerate
są nieprawidłowe.enumerate(l[1:])
należy zastąpićenumerate(l[1:], 1)
enumerate(l[1:])
przezenumerate(l[1:], 1)
was mógłby zastąpićl[i-1]
przezl[i]
.L5=range(100); random.shuffle(L5)
numer 5 jest stosunkowo wolny. W tym przypadku zmodyfikowany numer 7 jest ogólnie szybszy codepad.org/xmWPxHQYZrobiłbym to (kradnąc z wielu odpowiedzi tutaj [Aaron Sterling, Wai Yip Tung, trochę od Paula McGuire'a] i głównie Armin Ronacher ):
Jedna fajna rzecz: nie musisz zdawać sobie sprawy z drugiej iterowalnej dla serii (w przeciwieństwie do wycinka listy).
źródło
key
.key
należy używać do zamiany pozycji na porównywalne wartości.Używam tej jednej linijki opartej na numpy.diff ():
Tak naprawdę nie porównałem tego z żadną inną metodą, ale zakładam, że jest szybsza niż jakakolwiek czysta metoda Pythona, szczególnie dla dużego n, ponieważ pętla w numpy.diff (prawdopodobnie) działa bezpośrednio w C (n-1 odejmowania, po których następuje n -1 porównania).
Musisz jednak być ostrożny, jeśli x jest liczbą int bez znaku, co może powodować cichy niedopełnienie liczby całkowitej w numpy.diff (), powodując fałszywie dodatni wynik. Oto zmodyfikowana wersja:
źródło
Jest to podobne do pierwszej odpowiedzi, ale podoba mi się bardziej, ponieważ pozwala uniknąć jawnego indeksowania. Zakładając, że Twoja lista ma nazwę
lst
, możesz generować(item, next_item)
krotki z listy za pomocązip
:W Pythonie 3
zip
już zwraca generator, w Pythonie 2 możesz użyćitertools.izip
dla lepszej wydajności pamięci.Małe demo:
Ostatnia nie powiedzie się podczas oceny krotki
(3, 2)
.Bonus: sprawdzanie skończonych (!) Generatorów, których nie można indeksować:
Upewnij się, że używasz
itertools.izip
tutaj, jeśli używasz Pythona 2, w przeciwnym razie pokonałbyś cel, jakim jest brak konieczności tworzenia list z generatorów.źródło
islice
do optymalizacji pod kątem krojenia. Również w module itertools.all(x <= y for x, y in izip(lst, islice(lst, 1)))
.SapphireSun ma rację. Możesz po prostu użyć
lst.sort()
. Implementacja sortowania w Pythonie (TimSort) sprawdza, czy lista jest już posortowana. Jeśli tak, sort () zakończy się w czasie liniowym. Brzmi jak Pythonic, aby upewnić się, że lista jest posortowana;)źródło
Chociaż nie wydaje mi się, aby istniała gwarancja, że
sorted
wbudowana funkcja wywoła swoją funkcję cmp za pomocąi+1, i
, wydaje się, że robi to w przypadku CPythona.Możesz więc zrobić coś takiego:
Lub w ten sposób (bez instrukcji if -> EAFP poszło źle? ;-)):
źródło
Niezbyt Pythonic, ale potrzebujemy przynajmniej jednej
reduce()
odpowiedzi, prawda?Zmienna akumulator po prostu przechowuje tę ostatnio sprawdzaną wartość, a jeśli jakakolwiek wartość jest mniejsza niż poprzednia wartość, akumulator jest ustawiany na nieskończoność (a zatem na końcu nadal będzie nieskończoność, ponieważ „poprzednia wartość” będzie zawsze większa niż obecna).
źródło
Jak zauważył @aaronsterling, poniższe rozwiązanie jest najkrótsze i wydaje się najszybsze, gdy tablica jest posortowana i niezbyt mała: def is_sorted (lst): return (sort (lst) == lst)
Jeśli przez większość czasu tablica nie jest posortowana, pożądane byłoby użycie rozwiązania, które nie skanuje całej tablicy i zwraca wartość False, gdy tylko zostanie znaleziony nieposortowany prefiks. Oto najszybsze rozwiązanie, jakie udało mi się znaleźć, nie jest szczególnie eleganckie:
Korzystając z testu porównawczego Nathana Farringtona, zapewnia to lepszy czas działania niż użycie sortowanego (lst) we wszystkich przypadkach, z wyjątkiem uruchamiania na dużej posortowanej liście.
Oto wyniki testów wydajności na moim komputerze.
sortowane (lst) == lst rozwiązanie
Drugie rozwiązanie:
źródło
Jeśli chcesz najszybszego sposobu na tablice numpy, użyj numba , który, jeśli używasz conda, powinien być już zainstalowany
Kod będzie szybki, ponieważ zostanie skompilowany przez numba
i wtedy:
źródło
Wystarczy dodać inny sposób (nawet jeśli wymaga to dodatkowego modułu)
iteration_utilities.all_monotone
:Aby sprawdzić zamówienie DESC:
Istnieje również
strict
parametr, jeśli trzeba sprawdzić ściśle (czy kolejne elementy nie powinny być równe) ciągów monotonicznych.W twoim przypadku nie stanowi to problemu, ale jeśli twoje sekwencje zawierają
nan
wartości, niektóre metody zawiodą, na przykład posortowane:Zauważ, że
iteration_utilities.all_monotone
działa szybciej w porównaniu z innymi wymienionymi tutaj rozwiązaniami, szczególnie w przypadku niesortowanych danych wejściowych (patrz test porównawczy ).źródło
Leniwy
źródło
all(a <= b for a, b in zip(l, l[1:]))
l
jest generatorem i nie obsługuje krojenia.Python 3.6.8
źródło
Najprostszy sposób:
źródło
Wyprowadzona wartość redukcji jest 3-częściową krotką ( sortSoFarFlag , firstTimeFlag , lastElementValue ). Początkowo zaczyna się (
True
,True
,None
), który jest również stosowany jako wynik dla pustej listy (traktowane jako sortowane, bo nie ma out-of-order elementy). Gdy przetwarza każdy element, oblicza nowe wartości krotki (używając poprzednich wartości krotki z następnym elementem elementValue):Ostatecznym wynikiem redukcji jest krotka:
Pierwsza wartość to ta, która nas interesuje, więc używamy jej
[0]
do wyłapania jej z wyniku redukcji.źródło
Ponieważ nie widzę tej opcji powyżej, dodam ją do wszystkich odpowiedzi. Oznaczmy więc listę następująco
l
:źródło
Rozwiązanie wykorzystujące wyrażenia przypisania (dodane w Pythonie 3.8):
Daje:
źródło
W rzeczywistości jest to najkrótszy sposób na zrobienie tego za pomocą rekurencji:
jeśli to Posortowane, wyświetli True, w przeciwnym razie wydrukuje False
źródło
RuntimeError: maximum recursion depth exceeded
przypadku długich list. Spróbujany_list = range(1000)
.A co z tym? Proste i zrozumiałe.
źródło
Zdecydowanie działa w Pythonie 3 i nowszych wersjach dla liczb całkowitych lub ciągów:
==================================================== ===================
Inny sposób sprawdzenia, czy dana lista jest posortowana, czy nie
źródło