155 votes

En Clojure, quand dois-je utiliser un vecteur plutôt qu'une liste, et inversement ?

J'ai lu que les vecteurs ne sont pas des séquences, mais que les listes le sont. Je ne suis pas sûr de savoir pourquoi on utilise l'un plutôt que l'autre. Il semble que les vecteurs soient les plus utilisés, mais y a-t-il une raison à cela ?

1 votes

118voto

Rayne Points 14518

Une fois de plus, il semble que j'ai répondu à ma propre question en m'impatientant et en la posant dans #clojure sur Freenode. Heureusement que répondre à ses propres questions est encouragé sur Stackoverflow.com :D

J'ai eu une brève discussion avec Rich Hickey, dont 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

1 votes

Pendant que vous êtes sur freenode, passez du côté obscur et rejoignez #stackoverflow ! :-P

0 votes

En fait, j'avais l'habitude d'y tourner au ralenti. J'ai changé de client IRC et je n'ai jamais pensé à ajouter #stackoverflow à ma liste d'autojoints.

0 votes

Je suis un novice en Lisp, mais je me demandais si les vecteurs, les cartes et les ensembles brisaient d'une certaine manière l'idée que tout code est interchangeable avec les données ? Ou s'agit-il simplement d'une de ces choses qui font de Clojure un Lisp pratique (OR, peut-on évaluer un vecteur ?).

94voto

Chris Jester-Young Points 102876

Si vous avez beaucoup programmé en Java et que vous êtes familier avec le cadre de collection Java, vous pensez à des listes telles que LinkedList et des vecteurs tels que ArrayList . Vous pouvez donc à peu près choisir les conteneurs de la même manière.

Pour plus de clarté : si vous avez l'intention d'ajouter souvent des éléments individuellement à l'avant 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. En revanche, si vous souhaitez accéder fréquemment à des éléments spécifiques (qui ne se trouvent pas à l'avant ou à l'arrière de la liste) (accès aléatoire), vous devez utiliser un vecteur.

Par ailleurs, 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)

0 votes

Les vecteurs ne sont pas des séquences, mais ils sont séquentiels. (source : Rich lui-même sur #clojure sur freenode.) De plus, je ne connais pas du tout Java, mais Rich vient de répondre à ma question.

1 votes

Je modifierai mon message pour dire que les vecteurs peuvent être transformé en seqs, via la fonction seq :-)

2 votes

J'ai choisi votre réponse parce qu'elle répondait effectivement à la question, et je n'aime vraiment pas choisir mes propres réponses comme étant correctes. Cela ne me semble pas correct. Je vous remercie. :)

46voto

Svante Points 24355

Les vecteurs ont des temps d'accès aléatoires O(1), 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).

3 votes

Techniquement, les listes chaînées ont des temps d'accès O(1)... si vous n'accédez qu'à l'élément avant ou arrière :-P Cependant, les vecteurs ont des temps d'accès aléatoires O(1) :-)

4 votes

("Liste chaînée", telle que décrite ci-dessus, se réfère à des listes doublement chaînées. Les listes à lien unique n'ont qu'un accès O(1) à l'élément de tête. :-P)

1 votes

Pour quelqu'un qui vient de se plonger dans Clojure, c'est une bien meilleure réponse que les deux autres qui ont reçu le plus de votes. Les deux autres ne me disent rien d'utile.

30voto

mikera Points 63056

Quand utiliser un vecteur ?

  • Performance de l'accès indexé - Vous obtenez un coût ~O(1) pour l'accès indexé contre O(n) pour les listes.
  • L'ajout de - avec conj est ~O(1)
  • Notation pratique - Je trouve qu'il est plus facile de taper et de lire [1 2 3] que '(1 2 3) pour une liste littérale dans des circonstances où l'une ou l'autre fonctionnerait.

Quand utiliser une liste :

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

3 votes

Même en cas d'ajout/suppression aux deux extrémités, une liste est un choix peu judicieux. Un deque est bien meilleur (en CPU et surtout en mémoire). Essayer github.com/pjstadig/deque-clojure

2 votes

Re : le ~O(1) Pour les personnes à qui cette explication des coûts pourrait être utile - stackoverflow.com/questions/200384/constant-amortized-time

13voto

Arthur Ulfeldt Points 45059

Juste une petite note en passant :

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

les séquences sont plus génériques que les listes ou les vecteurs (ou les cartes ou les ensembles).
Il est regrettable que la REPL imprime les listes et les séquences de la même manière La fonction (seq ) crée une séquence à partir d'un grand nombre de choses différentes, y compris des listes, et vous pouvez ensuite transmettre cette séquence à une pléthore de fonctions qui font des choses intéressantes avec les 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 dispose d'un raccourci qui renvoie son argument s'il s'agit déjà d'un 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);
}

les listes sont des séquences, mais d'autres choses le sont également, et toutes les séquences ne sont pas des listes.

0 votes

Je ne veux pas m'attarder sur un petit point, c'est juste l'occasion de souligner quelque chose d'utile. beaucoup le savent déjà :)

2 votes

Ne voulez-vous pas dire class au lieu de class? ?

0 votes

Je ne sais pas si votre exemple a changé suite aux mises à jour de clojure (je pense que je suis sur 1.5), mais vos deux exemples retournent clojure.lang.PersistentList pour moi. Je suppose que vous vouliez écrire class no class? .

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X