В Clojure, когда я должен использовать вектор над списком, и наоборот? - PullRequest
137 голосов
/ 18 июля 2009

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

Ответы [ 5 ]

107 голосов
/ 18 июля 2009

Еще раз, похоже, я ответил на свой вопрос, проявив нетерпение и задав его в #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
81 голосов
/ 18 июля 2009

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

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

Кстати, векторы можно легко превратить в последовательности.

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)
37 голосов
/ 18 июля 2009

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

28 голосов
/ 24 ноября 2011

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

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

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

  • Когда вы хотите получить к нему доступ в виде последовательности (поскольку списки напрямую поддерживают seq без необходимости выделения новых объектов)
  • Prepending - добавление в начало списка с минусами или, предпочтительно, конъюнктурой O (1)
13 голосов
/ 21 июля 2009

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

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

последовательности являются более общими, чем списки или векторы (или карты или наборы).
К сожалению, REPL печатает списки и последовательности одинаково , потому что это действительно делает их похожими на списки, даже если они разные. функция (seq) создаст последовательность из множества различных вещей, включая списки, и вы можете затем передать этот 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);
}

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

...