Dla niektórych implementacjach Ruby, sortowania jest stabilna, ale nie powinieneś na tym polegać. Stabilność sortowania Ruby jest zdefiniowana przez implementację.
Co mówi dokumentacja
The documentation mówi, że nie powinno zależeć sortowania jest stabilna:
Wynik nie jest gwarancją stabilny. Gdy porównanie dwóch elementów zwraca 0, kolejność elementów jest nieprzewidywalna.
Należy zauważyć, że nie oznacza to, czy sortowanie jest stabilne. Po prostu mówi, że nie ma gwarancji, że będzie stabilny. Każda konkretna implementacja Rubiego może być stabilna i nadal zgodna z dokumentacją. Może również mieć niestabilny rodzaj lub zmienić, czy sortowanie jest stabilne w dowolnym momencie.
Co Ruby faktycznie robi
Ten test wydruki kodu true
jeśli sortowania Ruby jest stabilny, czy false
jeśli to nie jest:
Foo = Struct.new(:value, :original_order) do
def <=>(foo)
value <=> foo.value
end
end
size = 1000
unsorted = size.times.map do |original_order|
value = rand(size/10)
Foo.new(value, original_order)
end
sorted = unsorted.sort
stably_sorted = unsorted.sort_by do |foo|
[foo.value, foo.original_order]
end
p [RUBY_PLATFORM, RUBY_VERSION, RUBY_PATCHLEVEL, sorted == stably_sorted]
Poniżej znajdują się wyniki dla wszystkich Rubiny mam zainstalowane na moim Linuksie:
["java", "1.8.7", 357, false]
["java", "1.9.3", 551, false]
["x86_64-linux", "1.8.7", 374, false]
["x86_64-linux", "1.8.7", 374, false]
["x86_64-linux", "1.8.7", 376, false]
["x86_64-linux", "1.9.3", 392, false]
["x86_64-linux", "1.9.3", 484, false]
["x86_64-linux", "1.9.3", 551, false]
["x86_64-linux", "2.0.0", 643, false]
["x86_64-linux", "2.0.0", 648, false]
["x86_64-linux", "2.1.0", 0, false]
["x86_64-linux", "2.1.10", 492, false]
["x86_64-linux", "2.1.1", 76, false]
["x86_64-linux", "2.1.2", 95, false]
["x86_64-linux", "2.1.3", 242, false]
["x86_64-linux", "2.1.4", 265, false]
["x86_64-linux", "2.1.5", 273, false]
["x86_64-linux", "2.1.6", 336, false]
["x86_64-linux", "2.1.7", 400, false]
["x86_64-linux", "2.1.8", 440, false]
["x86_64-linux", "2.1.9", 490, false]
["x86_64-linux", "2.2.0", 0, true]
["x86_64-linux", "2.2.1", 85, true]
["x86_64-linux", "2.2.2", 95, true]
["x86_64-linux", "2.2.3", 173, true]
["x86_64-linux", "2.2.4", 230, true]
["x86_64-linux", "2.2.5", 319, true]
["x86_64-linux", "2.2.6", 396, true]
["x86_64-linux", "2.3.0", 0, true]
["x86_64-linux", "2.3.1", 112, true]
["x86_64-linux", "2.3.2", 217, true]
["x86_64-linux", "2.3.3", 222, true]
["x86_64-linux", "2.4.0", 0, true]
["x86_64-linux", "2.4.0", -1, true]
["x86_64-linux", "2.4.0", -1, true]
["x86_64-linux", "2.4.0", -1, true]
["x86_64-linux", "2.4.0", -1, true]
["x86_64-linux", "2.4.1", 111, true]
Widzimy, że JRuby jest niestabilny, a MRI przed 2.2, Linux, jest niestabilny. MRI> = 2.2.0 jest stabilny (ponownie, w systemie Linux).
Platforma ma jednak znaczenie. Chociaż powyższy wynik pokazuje, że porządek jest stabilny w MRI 2.4.1 w systemie Linux, ta sama wersja jest niestabilna w systemie Windows:
["x64-mingw32", "2.4.1", 111, false]
Dlaczego MRI rodzaj stabilny na Linuksie, ale nie na Windows?
Nawet w pojedynczej wersji implementacji Ruby algorytm sortowania może się zmienić. MRI może wykorzystywać co najmniej trzy różne rodzaje. Procedura sortowania jest wybierana podczas kompilacji przy użyciu serii #ifdefs w util.c. Wygląda na to, że MRI ma możliwość korzystania z sortów z co najmniej dwóch różnych bibliotek. Ma również własną implementację.
Co należy z tym zrobić?
Ponieważ sortowanie może być stabilne, ale nie można zagwarantować, że jest stabilne, nie należy pisać kodu, który zależy od stabilności sortowania Ruby. Ten kod mógł zostać złamany, gdy jest używany w innej wersji, implementacji lub platformie.
Nie, przynajmniej nie tak, jak to zrobiłeś. W jaki sposób "sortować" gwarantuje kolejność dwóch elementów, gdy ich dane komparatory są takie same? – Linuxios
@Linuxios: Niektóre algorytmy sortowania są [stabilne] (http://en.wikipedia.org/wiki/Stable_sort#Stability). –
@mu: Dzięki. Ciekawy. Nie sądzę jednak, żeby Ruby był. – Linuxios