Подтвердить что ты не робот

Clojure: последовательность обратно в вектор

Как я могу вернуть последовательность в вектор после операции создания последовательности (например, сортировка)? Использует ли использование (vec..) последовательность, являющуюся вектором, дорогостоящей?

Одна (плохая?) возможность создает новый вектор из последовательности:

(vec (sort [1 2 3 4 5 6]))

Я спрашиваю, потому что мне нужен произвольный доступ (nth..) к огромным отсортированным векторам - теперь это огромные последовательности после сортировки, с ужасным временем O (n) случайного доступа

4b9b3361

Ответ 1

Из моих собственных тестов (ничего научного) вам может быть лучше работать непосредственно с массивами в случаях, когда вы много сортируете. Но если вы редко разбираетесь и имеете много произвольного доступа, хотя, переход с помощью вектора может быть лучшим выбором, поскольку случайное время доступа в среднем более чем на 40% быстрее, но производительность сортировки ужасна из-за преобразования вектора в массив, а затем обратно к вектору. Здесь мои выводы:

(def foo (int-array (range 1000)))

(time
  (dotimes [_ 10000]
    (java.util.Arrays/sort foo)))

; Elapsed time: 652.185436 msecs

(time
  (dotimes [_ 10000]
    (nth foo (rand-int 1000))))

; Elapsed time: 7.900073 msecs

(def bar (vec (range 1000)))

(time
  (dotimes [_ 10000]
    (vec (sort bar))))

; Elapsed time: 2810.877103 msecs

(time
  (dotimes [_ 10000]
    (nth bar (rand-int 1000))))

; Elapsed time: 5.500802 msecs

P.S.: Обратите внимание, что векторная версия фактически не хранит отсортированный вектор в любом месте, но это не должно значительно изменить результат, поскольку вы использовали бы простые привязки в цикле для скорости.

Ответ 2

Meikel Brandmeyer только что опубликовал решение этого в группе Clojure.

(defn sorted-vec
  [coll]
  (let [arr (into-array coll)]
    (java.util.Arrays/sort arr)
    (vec arr)))

Clojure sort возвращает seq через отсортированный массив; этот подход делает то же самое, но возвращает вектор, а не seq.

Если вы хотите, вы даже можете перевести преобразование в структуру постоянных данных Clojure:

(defn sorted-arr
  "Returns a *mutable* array!"
  [coll]
  (doto (into-array coll)]
    (java.util.Arrays/sort))

но полученный массив Java (который вы можете рассматривать как коллекцию Clojure в большинстве случаев) будет изменчивым. Это прекрасно, если вы не передаете его другому коду, но будьте осторожны.

Ответ 3

Если вам нужен случайный доступ к результату сортировки с огромными векторами, тогда время, затрачиваемое на вызов vec, должно быть значительно перевешивается за счет экономии времени.

Если вы прокомментируете и обнаружите, что он слишком медленный, вам, вероятно, придется использовать java-массивы.

Ответ 4

Как новый разработчик Clojure, легко путать коллекции и последовательности.

Эта отсортированная векторная функция:

(sort [1 2 3 4 5 6]) = > (1 2 3 4 5 6); возвращает последовательность

Но мне нужен вектор для следующей операции, потому что это не работает...

(взятие-в то время (частичное > 3) (1 2 3 4 5 6))

= > ClassCastException java.lang.Long нельзя отнести к clojure.lang.IFn user/eval2251 (NO_SOURCE_FILE: 2136)

Попробуем преобразовать последовательность в вектор:

(vec (1 2 3 4 5 6))

= > ClassCastException java.lang.Long нельзя отнести к clojure.lang.IFn user/eval2253 (NO_SOURCE_FILE: 2139)

Неа! Но если вы все соедините, все будет хорошо.

(взятие-в то время (частичное > 3) (sort [1 2 3 4 5 6]))

= > (1 2)

Урок: вы не можете напрямую работать с последовательностями! Это промежуточный этап в этом процессе. Когда REPL пытается оценить (1 2 3 4 5 6), он видит функцию и генерирует исключение:

(1 2 3 4 5 6) = > ClassCastException java.lang.Long не может быть добавлено в clojure.lang.IFn user/eval2263 (NO_SOURCE_FILE: 2146)