Les tableaux


Quest-ce quun tableau

Un tableau est un type de donnée permettant de stocker plusieurs valeurs de manière séquentielle et dy accéder à laide dune seule variable.

Le moyen le plus simple de créer un tableau en python est dénumérer lensemble de ses valeurs:

>>> table = [1, 0, 5, -2, 4,]
>>> table
[1, 0, 5, -2, 4]

On vient ici de créer une variable table qui est un tableau (toute énumération de valeurs entre crochets [ ] sera interprétée comme un tableau par python).

Voyez ce quil se passe en sous-main à laide de python tutor:

définition d'un tableau

  • On voit très clairement quune zone de mémoire a été réservée pour stocker les 5 données de notre tableau. Cette zone est pointée par la variable table.
  • Cette représentation est extrêmement importante: en soit, une variable ne contient pas de valeur en python, elle est une référence (on dit un pointeur en informatique) vers une zone de la mémoire dans laquelle la ou les valeurs sont stockées. Cela aura une grande importance dans quelques temps, lorsque ce réseau de pointeurs sera plus compliqué.
  • Comme on peut le constater, les valeurs dun tableau sont indexées à partir de 0: la première valeur aura pour indice 0, la seconde aura pour indice 1, etc.

Pour accéder à la valeur dindice i, on utilise la syntaxe table[i]:

>>> table[0]
1
>>> table[1]
0
>>> table[2]
5
>>> table[3]
-2
>>> table[4]
5

Notons que le dernier élément du tableau a pour indice 4 alors que le tableau contient 5 éléments. Cest tout à fait normal: de 0 à 4, il y a exactement 5 valeurs.

On peut connaître le nombre déléments dun tableau à laide de la fonction len():

>>> len(table)
5

Attention, il nest pas possible daccéder à un élément dont lindice serait supérieur au dernier indice, cest-à-dire à la longeur moins 1. En particulier, table[len(table)] nexiste pas et provoquera une erreur.

Point très important: Le langage python autorise à stocker dans un tableau des données de type quelconque, sans aucune cohérence: on peut mettre des entiers, des nombres à virgule flottante, des chaînes de caractères dans un même tableau.

>>> mélange = ["pomme", 12, 3.14, "pêche"]
>>> mélange
["pomme", 12, 3.14, "pêche"]

Cependant, la plupart des autres langages nautorisent pas ce genre de lattitude: un tableau ne peut contenir quun type unique de données.

Afin déviter la prise de mauvaises habitudes, on sastreindra à partir de maintenant à ne jamais utiliser de tableau contenant des données mixtes.

Parcours dun tableau

Il nest pas envisageable dénumérer à la main tous les éléments dun tableau comme nous avons pu le faire dans un exemple précédent, dautant plus que le nombre déléments du tableau peut fort bien varier au cours de la durée de vie dun programme.

On utilisera avantageusement une boucle (pour ou tant que) afin daccéder à lensemble des éléments dun tableau.

Plusieurs cas de figure se présentent, selon que lon souhaite connaître lindice dun élément donné ou non.

Si on na pas besoin de connaître lindice dun élément

Dans ce cas, la boucle pour est de loin la plus adaptée. La syntaxe de cette boucle est dailleurs exactement conçue pour accéder aux éléments dun tableau:

prénoms = ["pascal", "pierre", "bérénice", "isabelle", "mathieu", "joachim", "anabelle"]
for p in prénoms:
  print(p)

Le résultat sera:

pascal
pierre
bérénice
isabelle
mathieu
joachim
anabelle

Si on a besoin de connaître lindice de chaque élément

Dans ce cas il existe plusieurs méthodes. On peut réutiliser la boucle précédente et compter les indices à la main:

i = 0
for p in prénoms:
    print("Le prénom d'incice", i, "est", p)
    i = i + 1
Le prénom d'incice 0 est pascal
Le prénom d'incice 1 est pierre
Le prénom d'incice 2 est bérénice
Le prénom d'incice 3 est isabelle
Le prénom d'incice 4 est mathieu
Le prénom d'incice 5 est joachim
Le prénom d'incice 6 est anabelle

Notons quil est indispensable dincrémenter à la main le compteur.

On peut aussi procéder autrement, en faisant boucler directement sur lindice i plutôt que sur lélément p. Il faudra dans ce cas utiliser la syntaxe suivante:

for i in range(len(prénoms)):
    print("Le prénom d'indice", i, "est", prénoms[i])
Le prénom d'indice 0 est pascal
Le prénom d'indice 1 est pierre
Le prénom d'indice 2 est bérénice
Le prénom d'indice 3 est isabelle
Le prénom d'indice 4 est mathieu
Le prénom d'indice 5 est joachim
Le prénom d'indice 6 est anabelle

Le résultat est exactement le même, mais lalgorithme sousjacent bien différent: on utiliser la fonction range() avec pour paramètre la longueur len(prénoms) du tableau: la variable i parcourera donc bien les entiers de 0 à len(prénoms) - 1. Pour accéder à lélément du tableau correspondant, on utilise alors la syntaxe prénoms[i] vue dans la partie précédente.

Notons quil nest pas nécessaire ici dincrémenter le compteur, cest la boucle pour qui sen charge.

On pourrait aussi remplacer celle-ci par une boucle tant que:

i = 0
while i < len(prénoms):
    print("Le prénom d'indice", i, "est", prénoms[i])
    i = i + 1
Le prénom d'indice 0 est pascal
Le prénom d'indice 1 est pierre
Le prénom d'indice 2 est bérénice
Le prénom d'indice 3 est isabelle
Le prénom d'indice 4 est mathieu
Le prénom d'indice 5 est joachim
Le prénom d'indice 6 est anabelle

Cela paraît plus compliqué parce quon est à nouveau obligé dincrémenter le compteur, mais la boucle tant que offre dautres avantages: on peut utiliser une condition plus compliquée, arrêter le parcours du tableau avant la fin (par exemple lorsque lon aura trouvé un élément que lon recherche). Nous verrons cela en exercice.

Modifier le contenu dun tableau

En python, un tableau nest pas une structure figée en mémoire. On peut notamment:

  • ajouter ou supprimer des éléments, à la fin, au début, voire même au milieu dun tableau
  • modifier une des valeurs stockée dans le tableau (ce qui revient en général à la remplacer par une autre).

Nous ne verrons pas toutes ces possibilités dans un premier temps, mais examinons les plus courantes.

Modifier un élément dun tableau

Pour modifier un élément dans un tableau, on utilise la syntaxe suivante:

>>> prénoms
['pascal', 'pierre', 'bérénice', 'isabelle', 'mathieu', 'joachim', 'anabelle']
>>> prénoms[1] = 'archibald'
>>> prénoms
['pascal', 'archibald', 'bérénice', 'isabelle', 'mathieu', 'joachim', 'anabelle']

On constate que le contenu du tableau a bien été modifié: son deuxième élément (donc dindice 1) a été remplacé par un autre. On dit en informatique quun tableau est une donnée variable, cest-à-dire que son contenu peut être modifié en mémoire (ce nest pas toujours le cas, comme nous le verrons plus tard, il y a aussi en python des données immuables comme par exemple les chaînes de caractères).

Ajouter un ou plusieurs éléments à la fin dun tableau

Lajout délements nest pas la même chose que la modification dun élément vue au paragraphe précédent: le contenu dune des cases mémoire était simplement remplacé par un autre, alors quici nous voulons modifier la taille du tableau. Python est extrêmement souple sur ce point, et autorise tous les changements de taille, tant quil reste de la mémoire disponible.

Pour ajouter un unique élément à un tableau, on peut utiliser la fonction append(élément) appliquée directement au tableau, comme suit:

>>> prénoms
['pascal', 'pierre', 'bérénice', 'isabelle', 'mathieu', 'joachim', 'anabelle']
>>> prénoms.append('maximilien')
>>> prénoms
['pascal', 'pierre', 'bérénice', 'isabelle', 'mathieu', 'joachim', 'anabelle', 'maximilien']

On constate que la fonction append(donnée) ne renvoie aucune valeur significative. Par contre elle agit bien sur le tableau, et en modifie la structure. On dit que append est une fonction qui possède un effet de bord (cest-à-dire que son but nest pas de renvoyer une valeur, mais daffecter son environnement, ici la mémoire de lordinateur).

Pour supprimer le dernier élément dun tableau, il y a la fonction pop() (sans arguments): celle-ci supprime effectivement lélément de plus grand indice, et renvoie sa valeur. Attention, pop() utilisé sur un tableau vide [] renverra une erreur puisquil ny a pas délément à supprimer.

>>> prénoms.pop()
'maximilien'
>>> prénoms
['pascal', 'pierre', 'bérénice', 'isabelle', 'mathieu', 'joachim', 'anabelle']

Nous constatons que pop() a bien renvoyé la valeur du dernier élément du tableau, et la effacé de celui-ci: cest une fonction à effet de bord, qui renvoie en outre une valeur intéressante.

Concaténation de deux tableaux

On a souvent besoin de prendre deux tableaux et de les concaténer, cest-à-dire les mettre bout à bout. Il existe deux manière de procéder en python.

Supposons que lon ait deux tableaux:

>>> t1 = [1, 2, 3, 4]
>>> t2 = [5, 6, 7, 8]

Lopération + entre deux tableaux ne réalise pas une addition (cela naurait aucun sens), mais crée un nouveau tableau contenant la concaténation des deux premiers. Il est important de remarquer quaucun des deux tableaux initiaux nest modifié par cette opération.

>>> t1 + t2
[1, 2, 3, 4, 5, 6, 7, 8]
>>> t1
[1, 2, 3, 4]
>>> t2
[5, 6, 7, 8]

Observez ces manipulations basiques à laide de python tutor.

Si on ne veut pas perdre immédiatement le résultat de t1 + t2, il est tout à fait possible de le stocker dans une nouvelle variable, voire même dans une variable existante. Par exemple, on peut vouloir remplacer t1 par la concaténation de t1 et t2, comme suit:

>>> t1 = t1 + t2
>>> t1
[1, 2, 3, 4, 5, 6, 7, 8]
>>> t2
[5, 6, 7, 8]

Observez cette différence fondamentale de comportement par rapport à lexécution dynamique précédente: python tutor.

Ajout dun tableau au bout dun autre

Il est possible de réaliser directement lopération précédente à laide de la fonction extend(tableau):

>>> t1 = [1, 2, 3, 4]
>>> t2 = [5, 6, 7, 8]
>>> t1.extend(t2)
>>> t1
[1, 2, 3, 4, 5, 6, 7, 8]
>>> t2
[5, 6, 7, 8]

Le résultat semble être le même que pour la syntaxe t1 = t1 + t2 précédente, mais ce nest pas exactement le cas: extend() va modifier le tableau t1 pour lui rajouter directement les éléments de t2 (un peu comme si on avait utilisé append pour chacun des éléments de t2 sur t1). En revanche, t1 = t1 + t2 crée dabord un nouveau tableau, qui est ensuite stocké dans t1. Lancien tableau qui était dans t1 nétant plus référencé par aucune variable, il sera effacé de la mémoire par python dès que possible.

Pour ce rendre compte de cette différence fondamentale, examinons une situation où une autre variable pointe sur même tableau que t1:

Avec une concaténation

Déroulé avec python tutor lorsque lon utilise la concaténation par lopérateur +.

Après avoir créé la variable copie_t1 pointant sur le même tableau que t1, on observe très clairement le partage des données en mémoire (il est très courant que plusieurs variables pointent sur une même valeur, mais comme nous allons le voir, ce nest pas sans dangers).

Après avoir exécuté la ligne t1 = t1 + t2, la variable t1 pointe bien sur la concaténation des deux tableaux, mais la variable copie_t1 est restée sur sa valeur initiale (cest probablement ce que lon souhaitait obtenir de toutes façons):

Avec extend

Déroulé avec python tutor lorsque lon utilise extend.

Avant lexécution dextend, la situation est 100% identique à la précédente:

Par contre, la fonction extend modifie le tableau pointé par t1 (et donc aussi par copie_t1) en place, et ce sans modifier aucun pointeur. On aboutit donc à la situation suivante:

La variable copie_t1 a elle aussi été affectée par extend, et ce nest probablement pas leffet recherché par le programmeur.

À retenir: Lorsque lon modifie des variables en place (cest-à-dire avec un effet de bord), cela peut potentiellement engendrer des erreurs dans le programme dès lors que des données sont partagées, ce qui est extrêmement courant.

Création de tableaux de taille arbitraire

On peut vouloir créer un tableau contenant par exemple 100 éléments, initialement tous à zéro. Il existe déjà un moyen de faire cela en létat de nos connaissances: utiliser un tableau initialement vide, et lui rajouter 100 fois lélément 0 à laide de append

t = []
for i in range(100):
    t.append(0)

Le tableau t contient alors les valeurs suivantes:

'[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
  0, 0, 0, 0, 0, 0, 0, 0, 0, 0]'

Il existe cependant une syntaxe spéciale en python qui permet de réaliser cela: lopération * appliqué entre un tableau et un nombre (dans cet ordre) va dupliquer le tableau autant de fois quindiqué par le nombre.

>>> t = [0] * 25
>>> repr(t)
'[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]'

Note: La fonction repr permet dafficher une valeur telle que lon aurait dû la taper pour la saisir en python (cela évite notamment que le tableau soit affiché sur 100 lignes dans la cellule. Essayez sans le repr() pour vous en rendre compte)

À noter que ce mécanisme de duplication fonctionne quelle que soit la taille du tableau initial:

>>> t = [0, 1] * 25
>>> repr(t)
'[0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1]'

On utilisera souvent cette syntaxe pour initialiser des tableaux dont on sait à lavance (en début dalgorithme) quelle sera leur taille.

Mécanisme de compréhension de listes