web-dev-qa-db-fra.com

Dans Clojure, quand dois-je utiliser un vecteur sur une liste, et inversement?

J'ai lu que les vecteurs ne sont pas des séquences, mais les listes le sont. Je ne sais pas quelle est la raison d'être de l'un sur l'autre. Il semble que les vecteurs soient les plus utilisés, mais y a-t-il une raison à cela?

140
Rayne

Encore une fois, il semble que j'ai répondu à ma propre question en m'impatientant et en la posant dans #clojure sur Freenode. C'est une bonne chose de répondre à vos propres questions sur Stackoverflow.com: D

J'ai eu une discussion rapide avec Rich Hickey, et voici l'essentiel.

[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
109
Rayne

Si vous avez beaucoup programmé Java et que vous connaissez le cadre de collecte Java, pensez à des listes comme LinkedList et à des vecteurs) comme ArrayList. Vous pouvez donc à peu près choisir les conteneurs de la même manière.

Pour plus de précision: si vous avez l'intention d'ajouter beaucoup d'éléments individuellement au début ou à l'arrière de la séquence, une liste chaînée est bien meilleure qu'un vecteur, car les éléments n'ont pas besoin d'être mélangés à chaque fois. Cependant, si vous souhaitez accéder à des éléments spécifiques (pas près du début ou de l'arrière de la liste) fréquemment (c'est-à-dire un accès aléatoire), vous voudrez utiliser le vecteur.

Soit dit en passant, les vecteurs peuvent facilement être transformés en séquences.

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)
83
Chris Jester-Young

Les vecteurs ont O(1) temps d'accès aléatoires, mais ils doivent être préalloués. Les listes peuvent être étendues dynamiquement, mais l'accès à un élément aléatoire est O (n).

39
Svante

Quand utiliser un vecteur:

  • Performances d'accès indexé - Vous obtenez un coût de ~ O (1) pour l'accès indexé vs O(n) pour les listes
  • Ajout - avec conj est ~ O (1)
  • Notation pratique - je trouve qu'il est à la fois plus facile de taper et de lire [1 2 3] que '(1 2 3) pour une liste littérale dans les cas où l'un ou l'autre fonctionnerait.

Quand utiliser une liste:

  • Lorsque vous souhaitez y accéder en tant que séquence (puisque les listes prennent directement en charge seq sans avoir à allouer de nouveaux objets)
  • Prepending - ajouter au début d'une liste avec des inconvénients ou de préférence conj est O (1)
28
mikera

juste une petite note:

"J'ai lu que les vecteurs ne sont pas des séquences, mais les listes le sont." 

les séquences sont plus génériques que les listes ou les vecteurs (ou les cartes ou les ensembles).
Son regrettable que le REPL imprime les listes et les séquences de la même car cela donne vraiment l'impression que les listes sont des séquences même si elles sont différentes. la fonction (seq) créera une séquence à partir de beaucoup de choses différentes, y compris des listes, et vous pouvez ensuite alimenter cette séquence à n'importe quelle pléthore de fonctions qui font des choses astucieuses avec des séquences.

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 a un raccourci qui renvoie son argument s'il s'agit déjà d'une séquence:

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);
}

les listes sont des séquences, bien que d'autres choses le soient aussi, et toutes les séquences ne sont pas des listes.

13
Arthur Ulfeldt