Коллега должен был отсортировать массив объектов ActiveRecord в приложении для направляющих. Он попробовал очевидное Array.sort!
но это казалось удивительно медленным, беря 32 для массива 3 700 объектов. Так на всякий случай это были эти большие объекты, замедляющие вещи, он повторно реализовал вид путем сортировки массива маленьких объектов, затем переупорядочение исходного массива ActiveRecord возражает против соответствия - как показано в коде ниже. Tada! Вид теперь берет 700 мс.
Это действительно удивило меня. Метод сортировки Ruby заканчивает тем, что копировал объекты о месте, а не просто ссылках? Он использует Ruby 1.8.6/7.
def self.sort_events(events)
event_sorters = Array.new(events.length) {|i| EventSorter.new(i, events[i])}
event_sorters.sort!
event_sorters.collect {|es| events[es.index]}
end
private
# Class used by sort_events
class EventSorter
attr_reader :sqn
attr_reader :time
attr_reader :index
def initialize(index, event)
@index = index
@sqn = event.sqn
@time = event.time
end
def <=>(b)
@time != b.time ? @time <=> b.time : @sqn <=> b.sqn
end
end
sort
определенно не копирует объекты. Одно различие, которое я могу представить между кодом, использующим EventSorter, и кодом без него (который вы не предоставили, поэтому я должен догадаться) заключается в том, что EventSorter вызывает event.sqn
и event.time
ровно один раз и сохраняет результат в переменных. Во время сортировки нужно иметь доступ только к переменным. Исходная версия предположительно вызывала sqn
и time
каждый раз при вызове блока сортировки.
Если это так, это можно исправить, используя sort_by вместо sort. sort_by вызывает блок только один раз для каждого объекта, а затем использует кешированные результаты блока для дальнейших сравнений.
Ничто не отвечает на подобные вопросы лучше, чем исходный код реального языка. Массив # sort! использует sort_internal (), который определен в array.c:
(Да, я знаю, что это источники для 1.8.4, но я не могу найти источники 1.8.6 в Интернете, и я почти уверен, что это не изменилось.)
Просто в качестве объяснения того, что, вероятно, происходит и как с этим бороться...
Сортировка имеет тенденцию просматривать элемент несколько раз, поэтому дорогой поиск в объекте или структуре быстро станет очень дорогим.
Шварцевское преобразование обычно используется при сортировке массивов сложных объектов или структур. Основная идея заключается в том, чтобы предварительно вычислить простое значение, которое точно отражает большую структуру или объект, затем отсортировать значения, а затем использовать полученный отсортированный массив для возврата к тому, из чего они были получены.