2010-01-01 4 views
16

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

One (плохо?) Возможность создания нового вектора из последовательности:

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

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

ответ

5

Из моих собственных тестов (ничего научного) вам может быть лучше работать непосредственно с массивами в случаях, когда вы делаете много сортировки. Но если вы редко разбираетесь и имеете много произвольного доступа, хотя, переход с помощью вектора может быть лучшим выбором, поскольку случайное время доступа в среднем более чем на 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 .: Обратите внимание, что вектор версия фактически не хранить отсортированный вектор в любом месте, но это не должно изменить результат значительно, как вы будете использовать простые привязки в петле для скорости.

+0

Nice. Теперь легко видеть, что выполнение (vec) на отсортированном векторе в 4 раза медленнее сортировки прямых массивов! Случайное время доступа так быстро и в векторе, и в массиве, что 40% не имеет значения, я думаю. – GabiMe

4

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

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

+0

Вот что я делаю сейчас. вызов vec. Но интересно, есть ли какой-то лучший способ – GabiMe

7

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 в большинстве случаев) будет изменчивым , Это нормально, если вы не передаете его другому коду, но будьте осторожны.

+0

Должно быть java.util.Arrays/sort (он забыл s). Но если это то же самое, как это происходит в 4 раза быстрее? Я опубликовал в группе Clojure тайминги. – GabiMe

+0

Это не в 4 раза быстрее, по крайней мере, на виртуальной машине сервера (которую вы должны использовать). c.c.sort использует явный компаратор и возвращает seq. Он также обращается к массиву, а не к массиву: первый возвращает массив объектов, в то время как последний возвращает типизированный массив. Помимо тех вещей, которые делают сортировку более общей, это тот же код. Эти общности стоят. Вся цель этого упражнения - избежать некоторых из этих работ; поэтому эта версия работает быстрее. – Rich

+1

вот нить http://groups.google.com/group/clojure/browse_thread/thread/d5b1152c9647d0fb# –

-1

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

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

(вид [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 пользователь/eval2251 (NO_SOURCE_FILE: 2136)

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

(VEC (1 2 3 4 5 6))

=> ClassCastException java.lang. Длинные нельзя отбрасывать в clojure.lang.IFn user/eval2253 (NO_SOURCE_FILE: 2139)

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

(бери в то время как (частичный> 3) (вид [1 2 3 4 5 6]))

=> (1 2)

Урок: Вы не можете работать с последовательностями напрямую! Это промежуточный этап в этом процессе. Когда РЕПЛ пытается оценить (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)

+1

Это вводит в заблуждение. Оценка '(sort [1 2 3 4 5 6])' в REPL, за которой следует '(take-while (partial> 3) * 1)' отлично работает. Если вы просто берете строковое представление последовательности, вы теряете информацию о типе. –

Смежные вопросы