Mam szereg skrótów:
[
{ :foo => 'foo', :bar => 2 },
{ :foo => 'foo', :bar => 3 },
{ :foo => 'foo', :bar => 5 },
]
Próbuję posortować tę tablicę w kolejności malejącej zgodnie z wartością :bar
w każdym haszu.
Używam sort_by
do sortowania powyżej tablicy:
a.sort_by { |h| h[:bar] }
Jednak sortuje tablicę w kolejności rosnącej. Jak ustawić sortowanie w kolejności malejącej?
Jednym z rozwiązań było wykonanie następujących czynności:
a.sort_by { |h| -h[:bar] }
Ale ten znak negatywny nie wydaje się odpowiedni.
sort_by.reverse
jest znacznie bardziej wydajna niż obecnie akceptowana odpowiedź. Uważam, że lepiej rozwiązuje również wspomnianą powyżej obawę dotyczącą „przekazywania intencji kodu”. Ponadto Tin Man zaktualizował swoją odpowiedź na aktualną wersję rubinu. To pytanie obejrzano ponad 15 000 razy. Jeśli możesz zaoszczędzić nawet 1 sekundę czasu każdego widza, myślę, że warto.Odpowiedzi:
Zawsze dobrze jest przeprowadzić analizę porównawczą różnych sugerowanych odpowiedzi. Oto, co odkryłem:
Myślę, że interesujące jest to, że @ Pablo's
sort_by{...}.reverse!
jest najszybszy. Przed uruchomieniem testu myślałem, że będzie on wolniejszy niż „-a[:bar]
”, ale zanegowanie wartości okazuje się dłuższe niż odwrócenie całej tablicy w jednym przebiegu. Nie jest to duża różnica, ale każde małe przyspieszenie pomaga.Oto wyniki dla Ruby 1.9.3p194 (wersja 2012-04-20, wersja 35410) [x86_64-darwin10.8.0]:
Są na starym MacBooku Pro. Nowsze lub szybsze maszyny będą miały niższe wartości, ale różnice względne pozostaną.
Oto nieco zaktualizowana wersja na nowszy sprzęt i wersja 2.1.1 Ruby:
Nowe wyniki z uruchomieniem powyższego kodu przy użyciu Ruby 2.2.1 na nowszym Macbooku Pro. Znów dokładne liczby nie są ważne, to ich relacje:
Zaktualizowano dla Ruby 2.7.1 na MacBooku Pro z połowy 2015 roku:
Źródłem
Array#reverse
jest:do *p2-- = *p1++; while (--len > 0);
kopiuje wskaźniki do elementów w odwrotnej kolejności, jeśli dobrze pamiętam moje C, więc tablica jest odwrócona.źródło
Szybka rzecz, która oznacza zamiar malejącego porządku.
(Pomyśli lepszy sposób w międzyczasie);)
źródło
Mógłbyś:
źródło
sort_by
chodziło o to, żeby uniknąć wielokrotnego uruchamiania funkcji porównywaniasort_by
jest o wiele bardziej wydajny i czytelniejszy. Negowanie wartości lub wykonanie odwrotności na końcu będzie szybsze i bardziej czytelne.* -1
nie działa ze wszystkimi wartościami (np. Czas) ireverse
ponownie uporządkuje wartości, które zostały posortowane jako równeWidzę, że mamy (oprócz innych) w zasadzie dwie opcje:
i
Chociaż oba sposoby dają taki sam wynik, gdy klucz sortowania jest unikalny, pamiętaj, że
reverse
sposób odwróci kolejność kluczy, które są równe .Przykład:
Chociaż często nie musisz się tym przejmować, czasem tak jest. Aby uniknąć takiego zachowania, możesz wprowadzić drugi klucz sortujący (który z pewnością musi być unikalny przynajmniej dla wszystkich elementów, które mają ten sam klucz sortujący):
źródło
reverse
jest inna. Wierzę, że to też zepsuje poprzedni rodzaj, w przypadku gdy ktoś próbuje zastosować wiele rodzajów w określonej kolejności.Co powiesz na:
To działa!!
źródło
sort
będzie działać, jest tylko szybszy podczas sortowania wartości bezpośrednich. Jeśli musisz poszukać dla nich,sort_by
jest to szybsze. Zobacz test.W odniesieniu do wspomnianego pakietu testów porównawczych wyniki te dotyczą również posortowanych tablic.
sort_by
/reverse
to jest:A wyniki:
źródło
Prostym rozwiązaniem od wstępującego do malejącego i odwrotnie jest:
SMYCZKI
CYFRY
źródło
Dla tych, którzy lubią mierzyć prędkość w IPS;)
I wyniki:
źródło