Données Tableaux

Identification

Infoforall

8 - Utilisation de tableaux de données


Nous allons maintenant formaliser plusieurs choses vues sur les tableaux et voir comment ils sont implémentés dans différents langages.

Cette activité comporte beaucoup de parties déjà rencontrées dans les activités de programmation Python.

Documents de cours : open document ou pdf

Evaluation ✎ : questions 5-6-7-8.

1 - Tableaux

Nous avons vu que les tableaux étaient un ensemble de données de même type comportant un nombre fixe de cases définies à la création du tableau.

On dit ainsi souvent que ces tableaux sont statiques dans la mesure où, une fois créé, on ne peut plus modifier leurs nombres d'éléments (par contre, on peut changer le contenu individuel de ces éléments).

Voyons maintenant pourquoi.

Voyons une petit partie des adresses mémoires d'un ordinateur. Ici, on a

  • Derrière Ad : le numéro-adresse de la case mémoire (donnée en décimal pour simplifier, mais souvent on les récupère en hexadécimal)
  • En rouge : l'octet stocké dans la case mémoire, exprimé également en base 10. Mais gardez bien à l'esprit qu'il s'agit physiquement d'un ensemble de 8 bits.
Contenu de la mémoire
Un petit apercu de la mémoire

01° Que vaut l'octet stocké à l'adresse 213 ? Convertir ce nombre N10 en base 2 de façon à visualiser les 8 bits réellement stockés à cet endroit.

...CORRECTION...

On voit qu'on y a stocké un octet correspont à N = 18 10

On doit donc activer le bit de poids 16.

Il reste 18-16 = 2 à encoder. On active le bit de poids 2.

On a donc N = 0001 0010 2

02° Peut-on savoir ce qui est stocké en mémoire si on ne connait pas l'encodage qui a été utilisé ?

...CORRECTION...

Et non. On ne peut pas le savoir

Lorsqu'on accède à la lecture de la mémoire octet par octet, on ne peut pas savoir ce qui a réellement été stocké. On peut au mieux faire des suppositions sur la signification de cette suite d'octets.

Il pourra s'agir d'entier signé encodé sur 2 octets (type short int), de flottants encodés sur 4 octets (type simple precision), sur des caractères encodés sur un octet (type char). Ou d'adresses mémoires encodées sur 4 octets ... Bref, impossible de savoir, à moins de reconnaitre un motif dans les octets.

Structure d'un tableau

Un tableau est caractérisé par plusieurs choses :

  • Une adresse mémoire initiale
  • Le type de données encodées dans les cases
  • Le nombre de cases dans le tableau

Imaginons que notre tableau contiennne des entiers naturels sur 4 octets.

Le premier entier stocké est donc encodé par la suite d'octets  45 200 21 75 

Mémoire avec groupement de 4 octets
Un petit apercu de la mémoire groupé par 4 octets

Le contenu 45 200 21 75 est en réalité un ensemble de 32 bits :

>>> f"{45:0>8b} {200:0>8b} {21:0>8b} {75:0>8b}" '00101101 11001000 00010101 01001011'

Que vaut ce premier entier ?

On doit lire les octets W, X, Y et Z puis calculer ceci :

Entier n = W * 224 + X * 216 + Y * 28 + Z * 20

Entier n = 45 * 224 + 200 * 216 + 21 * 28 + 75 * 20

Entier n = 768 087 371

Voilà. Nous avons donné un sens au premier élément car :

  1. Nous connaissons l'adresse de départ
  2. Nous connaissons le type d'encodage utilisé pour placer les données en mémoire : integer sur 4 octets.

Si nous cherchons les autres entiers encodés, il faudra donc également regrouper les octets par 4 et donner à chaque association un numéro d'indice. Commençons par le numéro 0 :

Mémoire avec groupement de 4 octets
Les indices correspondant aux groupements de 4 octets
Avantages et désavantages des tableaux

Nous pouvons maintenant comprendre l'avantage principal d'une structure de données de ce type : on peut accéder très facilement à n'importe quel élément du tableau pourvu qu'on connaisse son indice.

L'adresse visée est en effet : Adresse de départ + indice x taille d'une donnée en octets.

Exemple :

  • Tableau contenant des integers (sur 4 octets)
  • Adresse initiale : 200
  • Adresse de l'indice 0 : adresse = 200 + 0 * 4 = 200
  • Adresse de l'indice 1 : adresse = 200 + 1 * 4 = 204
  • Adresse de l'indice 2 : adresse = 200 + 2 * 4 = 208
  • ...

Vous avez maintenant l'explication de l'intérêt de prendre 0 comme numéro initial d'indice !

Avantages

La lecture des éléments n'est donc pas séquentielle : on peut accéder à l'élement 7 sans avoir dû lire les éléments 0-1-2-3-4-5-6.

Le temps d'accès à un élément est constant : on accède aussi rapidement à l'élément 200 qu'à l'élement 0 et cela que le tableau contienne 100 ou 100 000 éléments !.

Par contre, il y a trois désavantages principaux :

Il faut que les élements soient tous de même nature (et occupent dans le même nombre d'octets en mémoire)

Il faut que les zones mémoires soient contiguës. Il faut donc reserver la zone intialement : la taille est à définir à la création de façon à connaitre la dernière adresse.

On ne peut pas intercaler un nouvelle élément. Imaginons qu'on possède 4 éléments 0-1-2-3. Si on veut placer un élément entre le 0 et le 1, on va devoir déplacer d'abord les éléments 3 vers 4, 2 vers 3, 1 vers 2 et enfin placer le nouvel élément en indice 1.

03° Imaginons que notre tableau d'integers sur 4 octets possède 200 éléments. Quelle est l'adresse de l'élément d'indice 100 ?

...CORRECTION...

Il suffit de calculer 200+4*100 = 600.

Nous verrons plus tard d'autres structures de données ayant d'autres avantages et d'autres inconvénients. Comme toujours, il faudra étudier le problème et choisir ensuite la structure la plus adaptée à sa résolution.

Pour l'instant, nous nous limiterons aux tableaux.

2 - Tableau avec Python

1 - Déclaration d'un tableau en Python

Les éléments délimitateurs sont les crochets. Chaque élément du tableau est séparé des autres par une virgule.

Exemple

>>> t = ['a', 'b', 'c'] >>> t ['a', 'b', 'c'] >>> type(t) <class 'list'>

On voit que les "tableaux" sont en python des objets de classe list.

2 - Nombre d'éléments stockés

On peut utiliser la fonction native len pour obtenir le nombre d'éléments (ici des caractères pour le premier cas et des ints pour le deuxième cas) stockés dans le tableau.

Exemple

>>> t = ['a', 'b', 'c'] >>> nbr = len(t) >>> nbr 3
>>> t = [12.45, 5.0, 17.9, 4.32] >>> nbr = len(t) >>> nbr 4

On remarquera bien que dans les deux cas, nous avons des types list : on ne trouve pas d'indication directe sur le type des données contenues dans le tableau.

La variable t désigne ici le conteneur, pas le contenu.

3 - Accès à l'un des éléments

Pour accéder à l'un des éléments en particuliers, on peut noter le nom de la variable suivi de crochets et y placer l'indice du numéro voulu.

Exemple

>>> t = ['a', 'b', 'c'] >>> e0 = t[0] >>> e0 'a' >>> e1 = t[1] >>> e1 'b' >>> e2 = t[2] >>> e2 'c'

La correspondance indice - élément donne ceci sur l'exemple

Index 0 1 2
Elément 'a' 'b' 'c'
4 - Lecture des éléments un à un (méthode classique)

On peut aussi lire les éléments un par un en utilisant une boucle FOR couplée à la fonction len pour connaitre la valeur limite à placer pour l'indice d'incrémentation de la boucle.

Ainsi avec

 t_notes_A = [15, 18, 8, 10, 12, 15, 20, 5, 12, 17, 12, 10, 18, 4] 

Nous avons 14 éléments avec un indice 0-1-2-3-4-5-6-7-8-9-10-11-12-13.

Index 0 1 2 3 4 5 6 7 8 9 10 11 12 13
Elément 15 18 8 10 12 15 20 5 12 17 12 10 18 4

Il faudrait donc utiliser for i in range(14):

Exemple

1 2 3 4 5
notes = [15, 18, 8, 10, 12, 15, 20, 5, 12, 17, 12, 10, 18, 4] nbr = len(notes) for i in range(nbr): print(notes[i])

Ce programme va afficher ceci dans la console :

15 18 8 10 12 15 20 5 12 17 12 10 18 4

04° Un tableau référencé par la variable t possède 5 éléments. Donner les valeurs successives que va prendre la variable i si on utilise le code de la ligne 4.

4
for i in range(len(t)):

...CORRECTION...

On aura successivement 0, 1, 2, 3 et 4.

5 - Lecture des éléments un à un (méthode nominative)

Cette gestion nominative d'itérer les éléments n'existe pas dans tous les langages.

1 2 3 4 5 6 7 8 9
notes = [15, 18, 8, 10, 12, 15, 20, 5, 12, 17, 12, 10, 18, 4] for n in notes : if n > 12 : print("Bien : ", n) elif n < 8 : print("Pas bien : ", n) else : print("Moyen : ", n)

Ce programme affiche "Bien", "Pas bien" ou "Moyen" devant chaque note sans avoir à passer par l'indice :

Bien : 15 Bien : 18 Moyen : 8 Moyen : 10 Moyen : 12 Bien : 15 Bien : 20 Pas bien : 5 Moyen : 12 Bien : 17 Moyen : 12 Moyen : 10 Bien : 18 Pas bien : 4

Quelle boucle for utiliser ?

Si vous devez modifier l'un des éléments : boucle for avec indice indispensable.

Si vous devez différencier la gestion en fonction de la place de l'élément : boucle for avec indice indispensable.

Si vous devez simplement lire les éléments : boucle for nominative possible.

6 - Mutabilité des tableaux dans Python

Dans la majorité des langages, les tableaux sont mutables : cela veut dire qu'on peut modifier les contenus d'un tableau après sa création. On dit qu'on peut modifier l'état du tableau.

En Python, le type list est mutable. Nous considérerons donc que les tableaux sont mutables lors de notre utilisation de Python.

>>> t = ['a', 'b', 'c'] >>> t ['a', 'b', 'c'] >>> t[0] = 'Z' >>> t ['Z', 'b', 'c']

Avantage (ou désavantage !) concret de mettre du contenu dans un tableau ? On peut modifier l'état du tableau (son contenu) depuis une fonction sans avoir besoin de mettre le mot clé global : le nom de la variable ne sert qu'à localiser l'adresse-mémoire menant au contenu d'indice voulu.

Avant la modification :
Tableau mutable
Après la modification : tableau est toujours associé à Id12
Tableau mutable
7 - Effet de bord

En utilisant l'identifiant d'un tableau, on peut le modifier depuis l'intérieur d'une fonction sans avoir besoin de renvoyer le tableau.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
def multiplier(t, coef): """modifie le tableau t en multipliant chaque valeur par le coef fourni :: param t(list) :: un tableau ne contenant que des nombres entiers :: param coef(int) :: un entier servant de coefficient multiplicateur .. Effet de bord :: le paramètre t est modifié par la fonction-procédure :: exemple :: >>> tab_test = [1,2,10] >>> multiplier(tab_test, 60) >>> tab_test [60, 120, 600] """ for i in range(len(t)) : t[i] = t[i] * coef if __name__ == '__main__' : import doctest doctest.testmod()

Comme vous pouvez le voir, pas de return : t va contenir l'identifiant-mémoire du tableau fourni lors de l'appel. On pourra ainsi aller modifier le vrai tableau directement en manipulant les indices de la variable t.

✎ 05° Créer la fonction compter qui possède un paramètre t dans lequel on attend un tableau d'entiers. On compte dans cette fonction le nombre de notes supérieures à 10. On renvoie ce résultat.

Réfléxion : a-t-on vraiment besoin des indices ?

  • Oui, boucle for numérique dans la fonction.
  • Non, boucle for nominative.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
def compter(t): """Fonction qui renvoie le nombre d'éléments supérieurs à 10 dans le tableau t :: param t(list) :: un tableau ne contenant que des nombres entiers :: return(int) :: le nombre de notes supérieures à 10 .. Effet de bord :: Aucun : t ne doit pas être modifié :: exemple :: >>> notes = [1,2,10,15,18] >>> nbr = compter(notes) >>> nbr 2 """ pass if __name__ == '__main__' : import doctest doctest.testmod()

Fonction : il faudra un return.

✎ 06° Créer la procédure modifier qui attend en paramètre un tableau d'entiers. On remplace

  • les élements valant 10 ou plus par 20 et
  • les élements valant moins de 10 par 0.

S'agissant d'une procédure, on modifie donc le tableau par effet de bord.

Réfléxion : a-t-on vraiment besoin des indices ?

  • Oui, boucle for numérique dans la fonction.
  • Non, boucle for nominative.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
def modifier(t): """Procédure qui modifie les éléments du tableau t par 0 ou 20 :: param t(list) :: un tableau ne contenant que des nombres entiers :: return(None) :: procédure .. Effet de bord :: t est modifiée :: exemple :: >>> notes = [1,2,10,15,18] >>> modifier(notes) >>> notes [0, 0, 20, 20, 20] """ pass if __name__ == '__main__' : import doctest doctest.testmod()

Procédure : pas de return.

Point de détail : on notera qu'il ne s'agit pas réellement d'une procédure : Python ne sait gérer que des fonctions. Si on "oublie" le return, l'interpréteur va simplement créer une fonction qui renvoie None. On renvoie donc bien quelque chose enr réalité.

3 - Création d'un tableau en compréhension

Rappel

Déclaration de tableau par compréhension à partir d'un tableau initial

La déclaration d'un tableau par compréhension est celle qui consiste à formuler le contenu du tableau directement dans les crochets à l'aide d'une boucle for.

s = [None for v in t]
>>> t1 = [1, 2, 3] >>> s = [None for e in t1] >>> s [None, None, None]

En réalité, on peut faire mieux que mettre None dans chaque case : on peut indiquer le calcul à faire directement !

Voilà pour créer une copie contenant exactement le double dans chaque case qu'un tableau initial :

s = [v * 2 for v in t]
>>> t1 = [1, 2, 3] >>> s = [e*2 for e in t1] >>> s [2, 4, 6]

Si on veut l'intégrer dans une fonction :

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
def doubler(t): """Fonction qui renvoie un tableau où chaque élément est le double de l'élément correspondant du tableau t :: param t(list) :: un tableau ne contenant que des nombres entiers :: return (list) :: le tableau où chaque élément est le double de l'élément du même indice dans t :: exemple :: >>> doubler([1,2,3,4]) [2, 4, 6, 8] """ rep = [v * 2 for v in t] return rep if __name__ == '__main__' : import doctest doctest.testmod() tableau_test = [10,-2,-3,-4] t2 = doubler(tableau_test)

C'est beaucoup plus simple à écrire qu'avec un for. En réalité, l'interpréteur Python réalise en arrière plan la boucle for.

Déclaration de tableau par compréhension avec un range

On peut également créer des tableaux contenant un nombre précis d'élements de façon assez facile : il suffit d'utliser range.

>>> t = [0 for v in range(10)] >>> t [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
>>> t = [v*10 for v in range(10)] >>> t [0, 10, 20, 30, 40, 50, 60, 70, 80, 90]
>>> import random >>> t = [random.randint(1,100) for v in range(10)] >>> t [42, 41, 96, 35, 58, 94, 16, 21, 84, 51]

✎ 07° Créer par compréhension un tableau de 20 éléments contenant des nombres aléatoires compris entre 20 et 50.

✎ 08° Créer par compréhension un tableau de 500 éléments contenant 0.

On peut même faire mieux : on peut inclure des tests ou des fonctions dans la construction.

Premier exemple : on crée un tableau de 50 éléments compris entre 0 et 20. On crée un second tableau à partir du premier : on ne garde que les nombres supérieurs ou égaux à 10.

>>> import random >>> t = [random.randint(0,20) for v in range(50)] >>> t2 = [note for note in t if note >= 10] >>> t [12, 8, 1, 3, 3, 17, 8, 2, 2, 10, 15, 3, 16, 13, 5, 18, 12, 15, 19, 10, 9, 14, 0, 15, 11, 6, 11, 1, 10, 6, 17, 3, 17, 10, 9, 8, 1, 9, 7, 12, 15, 10, 15, 15, 9, 8, 18, 8, 9, 6] >>> t2 [12, 17, 10, 15, 16, 13, 18, 12, 15, 19, 10, 14, 15, 11, 11, 10, 17, 17, 10, 12, 15, 10, 15, 15, 18]

On peut enfin utiliser des fonctions lors de la création. Imaginons qu'on dispose de cette fonction en mémoire :

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
def pas_plus(valeur, seuil): """Fonction qui renvoie la valeur ou le seuil si la valeur est supérieure au seuil :: param valeur(int) :: l'entier à traiter :: param seuil(int) :: la valeur seuil maximale à renvoyer :: return (int) :: valeur ou seuil :: exemple :: >>> pas_plus(10,20) 10 >>> pas_plus(30,20) 20 """ if valeur > seuil : return seuil return valeur if __name__ == '__main__' : import doctest doctest.testmod()
>>> import random >>> t = [pas_plus(random.randint(0,20), 15) for v in range(10)] >>> t [14, 15, 7, 14, 11, 1, 13, 12, 15, 1]

On obtient bien un tableau de 10 éléments sans qu'aucun élément ne soit plus grand que 15.

4 - Tracer des graphiques

Les tableaux peuvent servir à stocker diverses informations.

On trouve les tableaux dans quasiment tous les programmes traitant de données.

Nous allons voir ici un cas typique : le tracé de graphiques.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
# 1 - Importation des modules nécessaires import math import matplotlib.pyplot as plt # 2 - Constantes # 3 - Déclaration des fonctions def f(x): """Renvoie la valeur f(x) renvoyée par la fonction voulue pour x ::param x (int/float) :: un nombre ::return (int/float) :: f(x) """ v = math.sqrt(x) return v # 4 - Programme principal # Création des tableaux de données tx = [ v/10 for v in range(1000) ] # Abscisse ty = [ f(x) for x in tx ] # Ordonnée xmax = max(tx) ymax = max(ty) # Création des courbes plt.plot(tx, ty, label="f(x)", color='orange') plt.xlabel("x") plt.ylabel("Racine de x") plt.title("Représentation de f(x)") plt.legend(loc='upper center') plt.axis([0, xmax, 0, ymax]) plt.grid() plt.show() # Affichage à l'écran des courbes

09° Tester ce programme pour vérifier qu'il affiche bien la courbe f(x) = √ x.

Représentation de la racine carrée

10° Que valent les valeurs minimale et maximale lorsqu'on utilise for v in range(1000) ?

...CORRECTION...

On part de 0 et on va jusqu'à 999. 1000 ne sera jamais atteint.

L'intervalle est bien [0;999]

11° Que valent les quatres premières valeurs et la valeur maximale du tableau lorsqu'on utilise la création par compréhension de la ligne 20 : tx = [ v/10 for v in range(1000) ] ?

...CORRECTION...

La valeur part en boucle de 0, 1, 2, 3 ... et on va jusqu'à 999. 1000 ne sera jamais atteint.

La liste contient donc des éléments valant 0, 0.1, 0.2, 0.3 jusqu'à 9.9

L'intervalle est bien [0.0;99.9]

12° Que valent les quatres premières valeurs de ty :  ty = [ f(x) for x in tx ]  ?

...CORRECTION...

La valeur part en boucle de 0, 1, 2, 3 ... et on va jusqu'à 999. 1000 ne sera jamais atteint.

La liste contient donc des éléments valant 0, 0.1, 0.2, 0.3 jusqu'à 9.9

L'intervalle est bien [0.0;99.9]

13° Que va renvoyer la fonction native max aux lignes 23 et 24 ?

...CORRECTION...

En ligne 23 : xmax contiendra 99.9

En ligne 24 : ymax contiendra la racine carré de 99.9

Quelques explications sur les dernières lignes :

27 28 29 30 31 32 33 34
plt.plot(tx, ty, label="f(x)", color='orange') plt.xlabel("x") plt.ylabel("Racine de x") plt.title("Représentation de f(x)") plt.legend(loc='upper center') plt.axis([0, xmax, 0, ymax]) plt.grid() plt.show() # Affichage à l'écran des courbes
  • L27 : Création de la courbe en fournissant la liste des abscisses, la liste des ordonnées, un label et une couleur
  • L28 : Légende sur l'axe X
  • L29 : Légende sur l'axe Y
  • L30 : Titre du graphiqe
  • L31 : Position des légendes
  • L32 : Liste des valeurs minimales et maximales sur les axes sous forme d'une liste : [Xmin, Xmax, Ymin, Ymax]
  • L33 : On affiche la grille à l'écran
  • L34 : On affiche la ou les courbes

Dernier exemple : on trace les représentations de racine carré de x, x et x carré sur l'intervalle [0;2[.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
# 1 - Importation des modules nécessaires import math import matplotlib.pyplot as plt # 2 - Constantes # 3 - Déclaration des fonctions # 4 - Programme principal # Création des tableaux de données tx = [ v/1000 for v in range(2000) ] # Abscisse ty1 = [ math.sqrt(x) for x in tx ] # Ordonnée ty2 = [ x for x in tx ] # Ordonnée ty3 = [ x**2 for x in tx ] # Ordonnée xmax = max(tx) ymax = max(ty3) # Création des courbes plt.plot(tx, ty1, label="f(x)", color='orange') plt.plot(tx, ty2, label="g(x)", color="red") plt.plot(tx, ty3, label="h(x)", color='green') plt.xlabel("x") plt.ylabel("Valeurs en ordonnée") plt.title("Représentation des fonctions") plt.legend(loc='upper center') plt.axis([0, xmax, 0, ymax]) plt.grid() plt.show() # Affichage à l'écran des courbes
Représentation des trois fonctions

5 - Tableau dans Javascript

Si vous voulez tester les codes présentés dans votre navigateur, il suffit de créer un fichier HTML ne comportant qu'une balise <script> et </script> et d'y placer le code Javascript fourni.

1 - Déclaration d'un tableau en Javascript

Les éléments délimitateurs sont les crochets. Chaque élément du tableau est séparé des autres par une virgule.

Exemple

1 2 3
var t = ['a', 'b', 'c']; console.log(t); console.log(typeof t);

Ce code affiche ceci dans la console Web

Array(3) [ "a", "b", "c" ] object

On voit que les tableaux sont en javascript des objets de classe Array (array voulant dire tableau en anglais).

2 - Nombre d'éléments stockés

On peut utiliser l'attribut length pour obtenir le nombre d'éléments (ici des caractères pour le premier cas et des ints pour le deuxième cas) stockés dans le tableau.

Exemple

var t = ['a', 'b', 'c']; var nbr = t.length; console.log(nbr);

Dans la console Web, on obtient ceci :

3

La variable t désigne ici le conteneur, pas le contenu.

3 - Accès à l'un des éléments

Pour accéder à l'un des éléments en particuliers, on peut noter le nom de la variable suivi de crochets et y placer l'indice du numéro voulu.

Exemple

var t = ['a', 'b', 'c']; var e0 = t[0]; console.log(e0); var e1 = t[1]; console.log(e1); var e2 = t[2]; console.log(e2);

Dans la console, l'affichage obtenu est :

a b c

La correspondance indice - élément donne ceci sur l'exemple

Index 0 1 2
Elément 'a' 'b' 'c'
4 - Lecture des éléments un à un (méthode classique)

On peut aussi lire les éléments un par un en utilisant une boucle FOR couplée à length pour connaitre la valeur limite à placer pour l'indice d'incrémentation de la boucle.

Ainsi avec

var t_notes_A = [15, 18, 8, 10, 12, 15, 20, 5, 12, 17, 12, 10, 18, 4] 

Nous avons 14 éléments avec un indice 0-1-2-3-4-5-6-7-8-9-10-11-12-13.

Index 0 1 2 3 4 5 6 7 8 9 10 11 12 13
Elément 15 18 8 10 12 15 20 5 12 17 12 10 18 4
1 2 3 4
var notes = [15, 18, 8, 10, 12, 15, 20, 5, 12, 17, 12, 10, 18, 4] for (var i = 0; i < notes.length; i=i+1) { console.log(notes[i]); }

Ce programme va afficher ceci dans la console Web :

15 18 8 10 12 15 20 5 12 17 12 10 18 4
5 - Lecture des éléments un à un (méthode nominative)

Cette gestion nominative d'itérer les éléments n'existe pas dans tous les langages.

1 2 3 4
var notes = [15, 18, 8, 10, 12, 15, 20, 5, 12, 17, 12, 10, 18, 4] for (var e of notes) { console.log(e); }

Ce programme affiche la même chose que le précédent. On notera la présence d'un for of là où Python possède un for in.

Ce programme va afficher ceci dans la console Web :

15 18 8 10 12 15 20 5 12 17 12 10 18 4

Quelle boucle for utiliser ?

Si vous devez modifier l'un des éléments : boucle for avec indice.

Si vous devez différencier la gestion en fonction de la place de l'élément : boucle for avec indice.

Si vous devez simplement lire les éléments : boucle for nominative.

6 - Mutabilité des tableaux dans Javascript

Dans la majorité des langages, les tableaux sont mutables : cela veut dire qu'on peut modifier les contenus d'un tableau après sa création. On dit qu'on peut modifier l'état du tableau.

En Javascript, le type list est mutable. Nous considérerons donc que les tableaux sont mutables lors de notre utilisation de Python.

var t = ['a', 'b', 'c']; t[0] = 'Z'; console.log(t);

Affichage dans la console :

Array(3) [ "Z", "b", "c" ]
7 - Effet de bord

Comme en python, en utilisant l'identifiant d'un tableau, on peut le modifier depuis l'intérieur d'une fonction sans avoir besoin de renvoyer le tableau.

En effet, la variable du tableau ne contient en réalité que l'adresse ou l'identifiant du tableau. Le paramètre de la fonction reçoit donc bien la vraie adresse et peut donc modifier le vrai tableau.

1 2 3 4 5 6 7 8 9 10 11 12 13 14
function multiplier(entree, coefficient) { /*PROCEDURE qui modifie le tableau entree en multipliant chaque valeur par le coefficient fourni :: param entree(array) :: un tableau ne contenant que des nombres entiers :: param coefficient(number) :: un nombre servant de coefficient multiplicateur .. Effet de bord :: le paramètre entree est modifié par la procédure */ for (var i = 0; i < entree.length; i=i+1) { entree[i] = entree[i] * coefficient; } } var test = [1,2,3]; multiplier(test,10); console.log(test);

Dans la console Web, on obtient alors ceci :

Array(3) [ 10, 20, 30 ]

Comme vous pouvez le voir, pas de return : entree va contenir l'identifiant du tableau fourni lors de l'appel. On pourra ainsi aller modifier le vrai tableau directement en manipulant les indices de la variable entree.

6 - Création par extension avec append

La création d'un tableau par extension et ajouts successifs consiste à rajouter des éléments les uns après les autres. Il s'agit donc d'une création progressive.

Cette partie ne fait pas partie des attendus de la 1er NSI. En première, vous n'aurez à gérer que des tableaux statiques : des tableaux dont le nombre de cases est fixé à la création.

Néanmoins, la création progressive d'une liste est pratique dans pas mal de situation. Puisqu'on a peut rajouter des cases au tableau après création, on parle de tableaux dynamiques.

Pourquoi préférer les tableaux statiques aux tableaux dynamiques en 1er ? Tout simplement pour des histoires de coûts. Rajouter des cases demandent bien entendu d'effectuer des opérations au niveau de la mémoire. Cela prend donc du temps et c'est assez compliqué à gérer. Il est donc indispensable que vous comprenniez bien que lorsqu'on utilise des tableaux dynamiques, ce n'est pas parce qu'une instruction tient sur une ligne que son coût est constant !

Nous avons déjà expliqué de nombreuses fois que les objets de classe list de Python ne sont pas vraiment des tableaux statiques.

Nous allons vous montrer ici qu'on peut rajouter des éléments à la fin d'un tableau de façon à augmenter son contenu. En 1er, nous n'utiliserons cette méthode que lors de la création, de façon à simuler le comportement d'un tableau statique classique.

Un exemple :

>>> a = [1,2,3] >>> a [1, 2, 3] >>> a.append(12) >>> a [1, 2, 3, 12]

On remarque bien que nous n'avons pas réalisé d'affectation : nous avons juste pris l'adresse du tableau (stocké dans a et utilisé la méthode append).

Il ne faut surtout pas écrire ceci :

>>> a = [1,2,3] >>> a = a.append(12) >>> a

14° Pourquoi ne faut-il par écrire a = a.append(12) à votre avis ?

...CORRECTION...

La méthode renvoie None. Le tableau est modifié par effet de bord.

Si vous utilisez le a = a.append(12), c'est donc comme si vous aviez noté a = None. C'est dommage : vous remplaçez la variable-tableau a par une variable-None.

De la même façon, append ne permet pas de rajouter les éléments d'un tableau à votre tableau : vous n'allez faire que rajouter le tableau entier en tant que tableau...

>>> b = [7,8,9] >>> a.append(b) >>> a [1, 2, 3, 12, [7, 8, 9]]

Maintenant que nous avons vu les deux principaux pièges de l'utilisation de append, voyons commment l'utiliser proprement pour créer un tableau.

  1. On crée un tableau vide. Par exemple : t = []
  2. On génère une boucle : for i in range(10):
  3. Dans cette boucle, on ajoute les éléments au fur et à mesure :

A titre d'exemple, voici le code permettant de générer un tableau contenant une suite d'entiers de 0 jusqu'à 90, de 10 en 10.

On notera qu'on peut faire exactement la même chose avec une création par compréhension.

1 2 3 4
t = [] for i in range(10): t[i].append(i*10)

15° Utiliser le code ci-dessous pour visualiser la création progressive du tableau. Lors de chaque passage en boucle, on rajoute un élément.

1 2 3 4 5
t = [] for i in range(10): t[i].append(i*10) print(t)

...CORRECTION...

[0] [0, 10] [0, 10, 20] [0, 10, 20, 30] [0, 10, 20, 30, 40] [0, 10, 20, 30, 40, 50] [0, 10, 20, 30, 40, 50, 60] [0, 10, 20, 30, 40, 50, 60, 70] [0, 10, 20, 30, 40, 50, 60, 70, 80] [0, 10, 20, 30, 40, 50, 60, 70, 80, 90]

7 - FAQ

J'ai vu qu'il y avait aussi un for in en Javascript !

C'est vrai. Mais il ne fonctionne pas comme cela de Python.

L'équivalence est bien for in Python équivalent au for of Javascript.

Voici l'effet d'un for in sur un tableau Array en javascript :

1 2 3 4
var notes = [15, 18, 8, 10, 12, 15, 20, 5, 12, 17, 12, 10, 18, 4] for (var e in notes) { console.log(e); }

Ce programme va afficher ceci dans la console Web :

0 1 2 3 4 5 6 7 8 9 10 11 12 13

La variable e contient donc en réalité l'indice du tableau, pas forcément l'élément sous pretexte qu'elle se nomme e.

Activité publiée le 26 01 2020
Dernière modification : 27 01 2020
Auteur : ows. h.