Séquences
Clojure définit de nombreux algorithmes en termes de séquences (seqs). Une seq est une liste logique et, contrairement à la plupart des Lisp où la liste est représentée par une structure concrète à deux emplacements, Clojure utilise l'interface ISeq pour permettre à de nombreuses structures de données d'accéder à leurs éléments sous forme de séquences. La fonction `seq` renvoie une implémentation de ISeq adaptée à la collection. Les seqs diffèrent des itérateurs en ce qu'elles sont persistantes et immuables ; elles ne sont pas des curseurs avec état pointant vers une collection. De ce fait, elles sont bien plus utiles que `foreach` : les fonctions peuvent consommer et produire des seqs, elles sont thread-safe, elles peuvent partager des structures,...
La plupart des fonctions de la bibliothèque de séquences sont paresseuses, c'est-à-dire que les fonctions qui renvoient des seqs le font de manière incrémentale, au fur et à mesure de leur consommation, et consomment donc également leurs arguments seq de manière incrémentale. Les fonctions renvoyant des seqs paresseuses peuvent être implémentées à l'aide de la macro `lazy-seq`. Voir aussi `lazy`.
Lorsque `seq` est utilisé sur des objets implémentant `Iterable`, la séquence résultante reste immuable et persistante, et représente un seul passage sur les données. Ce passage pouvant être effectué de manière paresseuse, il est possible qu'il prenne en compte des modifications survenues après l'appel à `seq`. De plus, si l'itérateur sous-jacent est sujet à une `ConcurrentModificationException`, la séquence résultante l'est également. Lorsque `seq` est utilisé sur des tableaux Java natifs, les modifications apportées au tableau sous-jacent sont répercutées dans la séquence ; il est nécessaire de copier le tableau source pour garantir une immuabilité totale. Cela dit, l'utilisation de `seq` sur les `Iterables` et les tableaux reste très utile, car les séquences prennent en charge les algorithmes multipasses et paresseux. Les programmes robustes ne doivent pas modifier les tableaux ou les `Iterables` contenant des séquences.
De nombreuses fonctions de la bibliothèque `seq` prennent une ou plusieurs collections en entrée, appellent `seq` sur ces collections, puis opèrent sur la séquence résultante. Autrement dit, nombre de ces fonctions prennent des collections en entrée, mais opèrent sur leurs séquences.
L'interface Seq
(Premier élément coll)
Renvoie le premier élément de la collection. Appelle la méthode seq sur son argument. Si coll est nil, renvoie nil.
(rest coll)
Renvoie la séquence des éléments suivant le premier. Appelle la fonction seq sur son argument. S'il n'y a plus d'éléments, renvoie une séquence logique pour laquelle seq renvoie nil.
(cons item seq)
Renvoie une nouvelle séquence où item est le premier élément et seq le reste.
Pour une explication de rest vs next et lazy-seq, voir lazy.
La bibliothèque Seq
Voici un aperçu des principales fonctions de séquence, regroupées selon leurs fonctionnalités. Certaines fonctions peuvent être utilisées de différentes manières et apparaissent donc dans plusieurs groupes. Vous trouverez de nombreuses autres fonctions dans la section API.
Depuis Clojure 1.7, Clojure propose également les transducteurs, un modèle alternatif pour les transformations composables sur les collections. Les transducteurs découplent les parties entrée, traitement et sortie d'une transformation et permettent sa réutilisation dans davantage de contextes, tels que les canaux core.async. La plupart des fonctions de séquence de la liste ci-dessous créent des transducteurs si la collection d'entrée est omise. Consultez la page Transducteurs pour plus de détails.
Séquence d'entrée, Séquence de sortie
| Catégorie | Fonctions |
|---|---|
| Séquence plus courte extraite d'une séquence plus longue | distinct filter remove for keep keep-indexed |
| Séquence plus longue issue d'une séquence plus courte | cons concat lazy-cat mapcat cycle interleave interpose |
| Séquence avec des éléments d'entête manquants | rest next fnext nnext drop drop-while nthnext for |
| Séquence avec des éléments de queue manquants | take take-nth take-while butlast drop-last for |
| Réarrangement d'une séquence | flatten reverse sort sort-by shuffle |
| Créer des séquences imbriquées | split-at splitv-at split-with partition partition-all partition-by partitionv partitionv-all |
| Traiter chaque élément d'une séquence pour créer une nouvelle séquence | map pmap mapcat for replace reductions map-indexed seque |
En utilisant une séquence
| Catégorie | Fonctions |
|---|---|
| Vérifier si une collection peut produire une séquence | seqable? |
| Extraire un élément numéroté spécifique d'une séquence | first ffirst nfirst second nth when-first last rand-nth |
| Construire une collection à partir d'une séquence | zipmap into reduce set vec into-array to-array-2d frequencies group-by |
| Transmettre les éléments d'une séquence comme arguments à une fonction | apply |
| Calculer un booléen à partir d'une séquence | not-empty some reduce seq? every? not-every? not-any? empty? |
| Rechercher une séquence à l'aide d'un prédicat | some filter |
| Évaluation de la force des séquences paresseuses | doseq dorun doall |
| Vérifiez si les séquences paresseuses ont été évaluées de force | realized? |
Création d'une séquence
| Catégorie | Fonctions |
|---|---|
| Séquence paresseuse de la collection | seq vals keys rseq subseq rsubseq |
| Séquence paresseuse issue de la fonction productrice | lazy-seq repeatedly iterate |
| Séquence paresseuse à partir d'une constante | repeat range |
| Séquence paresseuse provenant d'autres objets | line-seq resultset-seq re-seq tree-seq file-seq xml-seq iterator-seq enumeration-seq |