10. Listes

Jusqu’à présent, on n’a manipulé que des objets homogènes, c’est à dire contenant des valeurs de même nature (numérique, logique, chaîne de caractères). Les listes permettent de dépasser cette contrainte.

10.1. Caractéristiques de base

Comme le vecteur, la list est une séquence ordonnée d’éléments, possédant les caractéristiques suivantes:

  • elle peut être hétérogène

  • elle est indexable, c’est à dire qu’on peut accéder à ses éléments par leur position

  • on peut en extraire des sous listes (indexation sur une plage de positions)

  • on peut nommer ses éléments, ce qui autorise une indexation plus lisible que par position

La list peut être hétérogène, et il n’y a donc aucune contrainte sur la nature des éléments qui la constituent. Par exemple, une liste peut être constituée avec:

  • un vecteur numérique

  • une valeur logique

  • une matrice

  • un array de chaînes de caractères

  • une fonction

  • etc.

On crée une list avec la fonction list().

Important

Pour rappel, un vecteur est créé avec la fonction c(), un array avec la fonction array() et une matrice avec la fonction matrix().

Un exemple de liste:

> Lst <- list(name="Fred", wife="Mary", no.children=3, child.ages=c(4,7,9))
> names(Lst)
[1] "name"        "wife"        "no.children" "child.ages"

Important

Le caractère . est employé en R comme n’importe quel autre caractère alphanumérique pour la création de noms de variables ou de fonctions. Il ne possède pas comme dans d’autres langages (Python, Java, etc…) une signification particulière. Pour ces langages orientés objet, le . sépare les objets des méthodes qui leur sont associées.

On pourrait également construire la même liste en 2 étapes:

> Lst <- list("Fred", "Mary", 3, c(4,7,9))
> names(Lst) <- c("name", "wife", "no.children", "child.ages")

Une list est une structure dite récursive car elle peut contenir d’autres listes:

> x <- list(list(list(list())))
> str(x)
List of 1
 $ :List of 1
  ..$ :List of 1
  .. ..$ : list()

L’utilisation moderne de R fait un emploi massif de la data frame, qui est une super structure de la list et il est peu courant d’avoir à travailler directement sur une list. Il est cependant utile d’avoir vu quelques opérations élémentaires, tout en se souvenant qu’il y a probablement une bien meilleure façon de faire.

L’opérateur d’indexation de la liste est le double crochet [ et ]:

> Lst[[1]]
[1] "Fred"
> Lst[[4]]
[1] 4 7 9

Chaque élément de la list peut lui même être indexé suivant les règles vues précédemment. Puisque Lst[[4]] est un vecteur, on accède à ses éléments avec l’opérateur d’indexation du vecteur:

> Lst[[4]][1]
[1] 4

La fonction length() retourne le nombre d’éléments de la list:

> length(Lst)
[1] 4

Les éléments de la list peuvent être nommés et accédés via l’opérateur $ avec la syntaxe name$component_name. Ainsi :

  • Lst$name est une écriture allégée de Lst[[1]] et retourne la chaîne de caractères Fred

  • Lst$wife est une écriture allégée de Lst[[2]] et retourne la chaîne de caractères Mary

  • Lst$child.ages[1] est une écriture allégée de Lst[[4]][1] et retourne l’entier 4

Le code correspondant:

> Lst$name
[1] "Fred"

> Lst$wife
[1] "Mary"

> Lst$child.ages[1]
[1] 4

Si on doit extraire des éléments programmatiquement, l’opérateur d’indexation de liste [ ] est indispensable. Lst[["name"]] retourne le même résultat que Lst$name:

> x <- "name"
    > Lst[[x]]
[1] "Fred"

Avertissement

Lst[[1]] et Lst[1] ne retournent pas la même chose. [[ ]] est utilisé pour extraire un élément de la list, alors que [ ] retourne une list constituée du premier élément de Lst.

> class(Lst[[1]])
[1] "character"
> class(Lst[1])
[1] "list"

Astuce

On peut utiliser une abbréviation (non ambigüe) des noms associés à la syntaxe name$component_name. Par exemple, Lst$name peut être raccourci en Lst$na mais pas en Lst$n puisqu’il y aurait ambigïté avec Lst$no.children.

> Lst$name
[1] "Fred"

> Lst$na
[1] "Fred"

> Lst$n
NULL

10.2. Construction et modification de listes

On peut créer une liste avec la fonction list() avec une instruction de la forme:

> Lst <- list(name_1=object_1, …, name_m=object_m)

Avertissement

On peut omettre les noms en passant uniquement les objets constitutifs de la list mais ce n’est pas une bonne pratique.

On peut construire un vecteur constitué des éléments de la list avec la fonction unlist():

> x <- list(1,2)

> x
[[1]]
[1] 1

[[2]]
[1] 2

> unlist(x)
[1] 1 2

L’opération réciproque, c’est à dire la conversion d’un vecteur en list se fait avec la fonction de coercition as.list():

> as.list(1:2)
[[1]]
[1] 1

[[2]]
[1] 2

Les list, comme toutes les séquences ordonnées, peuvent être « étendues » par ajout d’éléments:

> Lst[5] <- list(matrix(1:6, nrow=2))
> Lst
$name
[1] "Fred"

$wife
[1] "Mary"

$no.children
[1] 3

$child.ages
[1] 4 7 9

[[5]]
     [,1] [,2] [,3]
[1,]    1    3    5
[2,]    2    4    6

Ajouter un élément de cette façon ne permet pas de le nommer:

> names(Lst)
[1] "name"        "wife"        "no.children" "child.ages"  ""

Il faut le faire « manuellement »:

> names(Lst)[5] <- c("mat")
> names(Lst)
[1] "name"        "wife"        "no.children" "child.ages"  "mat"
> Lst
$name
[1] "Fred"

$wife
[1] "Mary"

$no.children
[1] 3

$child.ages
[1] 4 7 9

$mat
     [,1] [,2] [,3]
[1,]    1    3    5
[2,]    2    4    6

10.2.1. Concaténation de list

Jusqu’à présent, la fonction de concaténation c() n’a été utilisée que pour les vecteurs, mais est utile pour d’autres structures de données. L’objet créé est de même nature que les arguments passés à c():

    > listA <- list(letters[1:3])
> class(listA)
[1] "list"
> listA
[[1]]
[1] "a" "b" "c"

> listB <- list(letters[4:6])
> listC <- list(letters[7:9])
> listABC <- c(listA, listB, listC)
> class(list.ABC)
[1] "list"
> list.ABC
[[1]]
[1] "a" "b" "c"

[[2]]
[1] "d" "e" "f"

[[3]]
[1] "g" "h" "i"