Clojure ленивые последовательности, которые являются векторами

StackOverflow https://stackoverflow.com/questions/3083535

Вопрос

Я заметил, что ленивые последовательности в 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 Возвращает ленивую последовательность), но результаты собираются и возвращаются в вектор.

Вектор растет по мере необходимости, мы добавляем только элементы до последнего запроса, и после вычисления это постоянный поиск времени.

Это было что-то вроде этого, вы имели в виду?

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top