Chcę posortować tablicę około 200-300 obiektów, sortując według określonego klucza i podanej kolejności (rosnąco / malejąco). Kolejność wyników musi być spójna i stabilna.
Jaki byłby najlepszy algorytm do użycia i czy możesz podać przykład jego implementacji w javascript?
Dzięki!
javascript
algorithm
sorting
William Casarin
źródło
źródło
Odpowiedzi:
Stabilne sortowanie można uzyskać dzięki niestabilnej funkcji sortowania.
Przed sortowaniem otrzymujesz pozycję wszystkich elementów. W twoim warunku sortowania, jeśli oba elementy są równe, sortujesz według pozycji.
Tada! Masz stabilny gatunek.
Napisałem o tym artykuł na swoim blogu, jeśli chcesz dowiedzieć się więcej o tej technice i jak ją wdrożyć: http://blog.vjeux.com/2010/javascript/javascript-sorting-table.html
źródło
Ponieważ szukasz czegoś stabilnego, sortowanie przez scalanie powinno wystarczyć.
http://www.stoimen.com/blog/2010/07/02/friday-algorithms-javascript-merge-sort/
Kod można znaleźć na powyższej stronie internetowej:
EDYTOWAĆ:
Zgodnie z tym postem wygląda to tak, jak Array.Sort w niektórych implementacjach używa sortowania przez scalanie.
źródło
Array#shift
może działać w czasie O (n), a więc twójmerge
w O (n * n).Nieco krótsza wersja tego samego, wykorzystująca funkcje ES2017, takie jak funkcje strzałek i destrukturyzacja:
Funkcjonować
Akceptuje tablicę wejściową i funkcję porównania:
Zwraca również nową tablicę zamiast sortowania w miejscu, jak wbudowana funkcja Array.sort () .
Test
Jeśli weźmiemy następującą
input
tablicę, początkowo posortowaną wedługweight
:Następnie posortuj go,
height
używającstableSort
:Prowadzi do:
Jednak sortowanie tej samej
input
tablicy za pomocą wbudowanejArray.sort()
(w Chrome / NodeJS):Zwroty:
Zasoby
Aktualizacja
źródło
stableSort
Funkcja jest naprawdę świetne rozwiązanie!Wiem, że odpowiedź na to pytanie jest już od jakiegoś czasu, ale tak się składa, że mam w schowku dobrą, stabilną implementację sortowania przez scalanie dla Array i jQuery, więc podzielę się nim w nadziei, że niektórzy przyszli użytkownicy uznają to za przydatne.
Umożliwia określenie własnej funkcji porównawczej, tak jak w przypadku zwykłej
Array.sort
implementacji.Realizacja
Przykładowe użycie
źródło
array.sort
, zobacz test tutaj dla ciągów i liczb całkowitych -> jsfiddle.net/QC64jmergeSort
i niesort
, więc nie jest przeznaczona do zastąpienia. Czasami wystarczy stabilne sortowanie przez scalanie, np. Podczas sortowania tabel według kolumn.Możesz użyć następującego wypełnienia, aby zaimplementować stabilne sortowanie niezależnie od natywnej implementacji, na podstawie stwierdzenia zawartego w tej odpowiedzi :
stableSort()
Wydaje się, że uruchomienie testów wydajności zaimplementowanych powyżej przebiega z prędkością około 57% szybkościsort()
przeglądarki Chrome w wersji 59-61.Użycie
.bind(compareFunction)
na opakowanej funkcji anonimowej w ramachstableSort()
zwiększyło tę względną wydajność z około 38%, unikając niepotrzebnych odwołań o określonym zakresie docompareFunction
przy każdym wywołaniu, przypisując je zamiast tego do kontekstu.Aktualizacja
Zmieniono operator trójskładnikowy na logiczne zwarcie, które zwykle działa lepiej (wydaje się, że powoduje 2-3% różnicę w wydajności).
źródło
Poniższe polecenie sortuje podaną tablicę, stosując dostarczoną funkcję porównania, zwracając oryginalne porównanie indeksu, gdy funkcja porównująca zwraca 0:
Poniższy przykład sortuje tablicę imion według nazwiska, zachowując kolejność jednakowych nazwisk:
źródło
jQuery.expando.split( "" ).sort( ( a, b ) => 0 ).join( "" ) === jQuery.expando
Oto stabilna implementacja. Działa przy użyciu natywnego sortowania, ale w przypadkach, gdy elementy są porównywane jako równe, zrywasz więzi, używając oryginalnej pozycji indeksu.
nieprecyzyjny test
inna odpowiedź nawiązywała do tego, ale nie opublikowała kodu.
ale nie jest szybki według mojego punktu odniesienia . Zmodyfikowałem metodę sortowania przez scalanie, aby zaakceptować niestandardową funkcję komparatora, i było to znacznie szybsze.
źródło
Możesz także użyć Timsort. To naprawdę skomplikowany algorytm (ponad 400 wierszy, stąd brak kodu źródłowego), więc zobacz opis Wikipedii lub użyj jednej z istniejących implementacji JavaScript:
Wdrożenie GPL 3 . Pakowane jako Array.prototype.timsort. Wydaje się być dokładnym przepisaniem kodu Java.
Implementacja w domenie publicznej Przykładowy kod, który jest samouczkiem, pokazuje jego użycie tylko z liczbami całkowitymi.
Timsort jest wysoce zoptymalizowaną hybrydą scalania i sortowania losowego i jest domyślnym algorytmem sortowania w Pythonie i Javie (1.7+). Jest to skomplikowany algorytm, ponieważ używa różnych algorytmów w wielu szczególnych przypadkach. Ale w rezultacie jest niezwykle szybki w różnych okolicznościach.
źródło
Proste jedno scalenieSort z http://www.stoimen.com/blog/2010/07/02/friday-algorithms-javascript-merge-sort/
źródło
Muszę sortować tablice wielowymiarowe według dowolnej kolumny, a następnie według innej. Używam tej funkcji do sortowania:
Zauważ, że ary.sort nigdy nie zwraca zera, co oznacza, że niektóre implementacje funkcji "sort" podejmują decyzje, które mogą być niewłaściwe.
To też jest cholernie szybkie.
źródło
Oto jak można rozszerzyć domyślny obiekt Array JS za pomocą prototypowej metody wykorzystującej MERGE SORT . Ta metoda pozwala na sortowanie według określonego klucza (pierwszy parametr) i podanej kolejności („rosnąco” / „desc” jako drugi parametr)
Możesz to sprawdzić samodzielnie, upuszczając powyższy fragment kodu w konsoli przeglądarki, a następnie próbując:
Lub uporządkuj na podstawie określonego pola w tablicy obiektów:
źródło
Potrzebowałem więc stabilnego sortowania dla mojej aplikacji React + Redux, a odpowiedź Vjeux pomogła mi. Jednak moje (ogólne) rozwiązanie wydaje się inne niż inne, które widzę tutaj do tej pory, więc udostępniam je na wypadek, gdyby ktoś inny miał pasujący przypadek użycia:
sort()
API, w którym mogę przekazać funkcję komparatora.Moim rozwiązaniem jest utworzenie tablicy o typie strukturalnym
indices
, a następnie użycie funkcji porównania do sortowania tych indeksów na podstawie tablicy, która ma być posortowana. Następnie możemy użyć posortowanego,indices
aby posortować oryginalną tablicę lub utworzyć posortowaną kopię w jednym przebiegu. Jeśli to jest mylące, pomyśl o tym w ten sposób: gdzie normalnie przekazujesz funkcję porównującą, taką jak:Zamiast tego używasz teraz:
Szybkość jest dobra; jest to w zasadzie wbudowany algorytm sortowania, plus dwa liniowe przebiegi na końcu i jedna dodatkowa warstwa wskaźnika pośredniego narzutu.
Z przyjemnością otrzymuję informacje zwrotne na temat tego podejścia. Oto moja pełna implementacja:
źródło
Wiem, że udzielono wielu odpowiedzi. Chciałem tylko opublikować krótki wpis dotyczący implementacji TS dla każdego, kto wylądował tutaj, szukając tego.
Metoda nie działa już w miejscu, jak robi to sortowanie natywne. Chcę też zaznaczyć, że nie jest to najbardziej wydajne. Dodaje dwie pętle rzędu O (n). chociaż samo sortowanie jest najprawdopodobniej O (n log (n)), więc jest mniejsze niż to.
Niektóre z wymienionych rozwiązań są bardziej wydajne, myśląc, że może to być mniej kodu, również przy użyciu wewnętrznego
Array.prototype.sort
.(Aby uzyskać rozwiązanie JavaScript, po prostu usuń wszystkie typy)
źródło
Zgodnie z blogiem deweloperów wersji 8, a caniuse.com
Array.sort
jest już stabilny zgodnie ze specyfikacją nowoczesnych przeglądarek, więc nie musisz tworzyć własnego rozwiązania. Jedynym wyjątkiem, jaki widzę, jest Edge, który wkrótce powinien przejść na chrom i również go wspierać.źródło
źródło
Sortowanie z liczeniem jest szybsze niż sortowanie przez scalanie (działa w czasie O (n)) i jest przeznaczone do stosowania na liczbach całkowitych.
Przykład:
źródło
array [3, 1, 3]
skróty do[undefined, 1, undefined, 3]
. Otrzymujemy dwie nieokreślone wartości, podczas gdy algorytm oczekuje, że będą ich trzy.