Clojure ленивые последовательности, которые являются векторами
-
28-09-2019 - |
Вопрос
Я заметил, что ленивые последовательности в Clojure, кажется, представляют собой внутренне как связанные списки (или, по крайней мере, они рассматриваются как последовательность с только последовательным доступом к элементам). Даже после того, как его кэшируется в память, время доступа к ленивому SEQ с nth
это o (n), не постоянное время как с векторами.
;; ...created my-lazy-seq here and used the first 50,000 items
(time (nth my-lazy-seq 10000))
"Elapsed time: 1.081325 msecs"
(time (nth my-lazy-seq 20000))
"Elapsed time: 2.554563 msecs"
Как мне получить постоянный поиск времени или создать ленивый вектор постепенно в Clojure?
Представьте, что во время поколения ленивого вектора каждый элемент является функцией всех элементов, предыдущих к нему, поэтому время, проведенное, проходящее в списке, становится значительным фактором.
Связанные вопросы включали только этот неполный фрагмент Java:Проектирование ленивого вектора: проблема с const
Решение
Да, последовательности в Cljure описаны как «Логические списки» с тремя операциями (во-первых, следующих и минусов).
Последовательность по существу является версией The Clojure ITERATOR (хотя CLOJURE.ORG настаивает на том, что последовательности не являются итераторы, поскольку они не удерживают состояния Iternal), а также могут перемещаться только через коллекцию подложки в линейной фронт-конечной форме.
Ленивые векторы не существуют, по крайней мере, не в Clojure.
Если вы хотите поиск постоянного времени по ряду индексов, без вычисления промежуточных элементов вам не нужно, вы можете использовать функцию, которая вычисляет результат на лету. В сочетании с воспоминанием (или кэшируя результаты в хэш ARG-REVESH самостоятельно) вы получаете почти такой же эффект, поскольку я предполагаю, что вы хотите от ленивого вектора.
Это, очевидно, работает только тогда, когда есть алгоритмы, которые могут вычислить F (n), более напрямую, чем проходить все предыдущие F (0) ... F (N - 1). Если такого алгоритма такого алгоритма, когда результат для каждого элемента зависит от результата для каждого предыдущего элемента, вы не можете сделать лучше, чем последовательность итератор в любом случае.
Редактировать
Кстати, если все, что вы хотите, это для результата, чтобы быть вектором, поэтому вы получаете быстрый поиск потом, и вы не против, что элементы создаются последовательно в первый раз, это достаточно просто.
Вот реализация фибоначчи с использованием вектора:
(defn vector-fib [v]
(let [a (v (- (count v) 2)) ; next-to-last element
b (peek v)] ; last element
(conj v (+ a b))))
(def fib (iterate vector-fib [1 1]))
(first (drop 10 fib))
=> [1 1 2 3 5 8 13 21 34 55 89 144]
Здесь мы используем ленивую последовательность, чтобы отложить вызовы функций, пока не спрашивают (iterate
Возвращает ленивую последовательность), но результаты собираются и возвращаются в вектор.
Вектор растет по мере необходимости, мы добавляем только элементы до последнего запроса, и после вычисления это постоянный поиск времени.
Это было что-то вроде этого, вы имели в виду?