В Clojure, когда я должен использовать вектор над списком и наоборот?

Я читал, что векторы не являются секциями, но являются списками. Я не уверен, в чем смысл использования одного над другим. Кажется, что векторы используются больше всего, но есть ли причина для этого?

Ответ 1

Еще раз, кажется, я ответил на свой вопрос, вызвав нетерпение и попросив его в # clojure на Freenode. Хорошая вещь, отвечающая на ваши вопросы, рекомендуется на Stackoverflow.com: D

У меня было быстрое обсуждение с Ричем Хики, и вот суть этого.

[12:21] <Raynes>    Vectors aren't seqs, right?
[12:21] <rhickey>   Raynes: no, but they are sequential
[12:21] <rhickey>   ,(sequential? [1 2 3])
[12:21] <clojurebot>    true
[12:22] <Raynes>    When would you want to use a list over a vector?
[12:22] <rhickey>   when generating code, when generating back-to-front
[12:23] <rhickey>   not too often in Clojure

Ответ 2

Если вы много программировали на Java и знакомы с каркасом Java-коллекции, подумайте о таких списках, как LinkedList и таких векторах, как ArrayList. Таким образом, вы можете выбирать контейнеры одинаково.

Для дальнейшего уточнения: если вы намерены добавлять элементы отдельно к фронту или задней части последовательности, связанный список намного лучше, чем вектор, потому что элементы не нужно перетасовывать каждый раз. Однако, если вы хотите часто использовать определенные элементы (не рядом с передним или задним списком) (т.е. Произвольный доступ), вам понадобится использовать вектор.

Кстати, векторы легко превращаются в seqs.

user=> (def v (vector 1 2 3))
#'user/v
user=> v
[1 2 3]
user=> (seq v)
(1 2 3)
user=> (rseq v)
(3 2 1)

Ответ 3

Векторы имеют O (1) случайное время доступа, но они должны быть предварительно распределены. Списки могут быть динамически расширены, но доступ к случайному элементу - O (n).

Ответ 4

Когда использовать вектор:

  • Индексированная производительность доступа - вы получаете ~ O (1) стоимость индексированного доступа против O (n) для списков
  • Добавление - с conj является ~ O (1)
  • Удобная нотация - мне легче набирать и читать [1 2 3], чем "(1 2 3)" для литерального списка в тех случаях, когда они будут работать.

Когда использовать список:

  • Если вы хотите получить к нему доступ в виде последовательности (поскольку списки напрямую поддерживают seq без необходимости размещения новых объектов)
  • Prepending - добавление к началу списка с минусами или предпочтительно conj является O (1)

Ответ 5

просто краткое примечание:
  

"I read that Vectors are not seqs, but Lists are." 

последовательности более общие, чем списки или векторы (или карты или наборы).
Несчастливо, что REPL печатает списки и последовательности одного и того же, потому что это действительно делает его похожим на списки - это последовательности, даже если они разные. функция (seq) будет создавать последовательность из множества разных вещей, включая списки, и вы можете затем передать этот фрагмент любому из множества функций, которые делают изящные вещи с помощью seqs.

user> (class (list 1 2 3))
clojure.lang.PersistentList

user> (class (seq (list 1 2 3)))
clojure.lang.PersistentList

user> (class (seq [1 2 3]))
clojure.lang.PersistentVector$ChunkedSeq

Sec имеет ярлык, который возвращает свой аргумент, если он уже является seq:

user> (let [alist (list 1 2 3)] (identical? alist (seq alist)))
true
user> (identical? (list 1 2 3) (seq (list 1 2 3)))
false

static public ISeq seq(Object coll){
        if(coll instanceof ASeq)
                return (ASeq) coll;
        else if(coll instanceof LazySeq)
                return ((LazySeq) coll).seq();
        else
                return seqFrom(coll);
}

списки - это последовательности, хотя есть и другие вещи, а не все последовательности - это списки.