python index num

Identification

Infoforall

23 - (Bilan) Tableaux


Nous avons déjà vu deux structures jouant le rôle de conteneurs indexés :

  • Les strings permettant de stocker des caractères. Les strings sont immuables après création.
  • Les tableaux permettant de stocker... n'importe quoi. Les tableaux sont muables en Python.

Aujourd'hui, nous allons faire un bilan de l'utilisation des tableaux statiques en Python.

Documents de cours : open document ou pdf

Logiciel nécessaire pour l'activité : Thonny ou juste Python 3

Evaluation : -

Résumé : Version HTML ou fond blanc ou ou PDF (couleur ou gris)

1 - Tableaux

Le tableau ressemble par de nombreux aspects au string mais il possède deux différences notables :

  1. On peut y stocker d'autres choses que des caractères
  2. Il est muable en Python  on peut changer le contenu d'une case du tableau sans changer l'adresse mémoire de la variable-tableau
1 - Tableau (statique) en informatique

Le mot tableau sera étudié plus en détail dans la partie DONNEES.

En informatique, un tableau statique (ou tableau tout court) est une structure de données ayant les propriétés suivantes :

  • Les données sont stockées dans des cases possèdant un numéro nommé indice (ou index en anglais).
  • Le nombre de cases est constant après l’initialisation.
  • Contenu homogène : même type de données dans toutes les cases du tableau.

Voici deux exemples de tableaux 

Un tableau de caractéres de taille 3

Indice Contenu
0 'A'
1 'B'
2 'C'

Un tableau de dictionnaires de taille 2

Indice Contenu
0 {'nom':'alice', 'classe':'1e1', 'nsi':True}
1 {'nom':'bob', 'classe':'1e4', 'nsi':True}
2 - Déclaration d'un tableau avec des crochets [] en Python (RAPPEL)

  1. Les éléments délimitateurs sont les crochets.
  2. Chaque élément du tableau est séparé des autres par une virgule.
  3. Cette structure est implémentée via le type list en Python.

Exemple

>>> t = ['a', 'b', 'c'] >>> t ['a', 'b', 'c'] >>> type(t) <class 'list'> >>> type(t) == list True
Que désigne une variable-tableau ?

La variable tab ci-dessous désigne le conteneur (l'armoire), pas le contenu de l'armoire.

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

Le type du conteneur est bien list (mais les éléments contenus sont eux des str).

En anglais et en C, un tableau statique s'appelle array.

3 - Nombre d'éléments stockés avec len() (RAPPEL)

La taille du tableau caractérise son nombre de "cases".

La fonction native len() renvoie le nombre d'éléments stockés dans le tableau.

Exemple

>>> tableau = ['a', 'b', 'c'] >>> len(t) 3 >>> nbr = len(t) >>> nbr 3
>>> t = [{'nom':'alice', 'classe':'1er1'}, {'nom':bob, 'classe':'1er4'}] >>> len(t) 2
4 - Accès à l'un des éléments avec [indice] (RAPPEL)

Pour accéder à l'un des éléments, on note le nom de la variable-tableau suivi de crochets et on y place l'indice du numéro voulu.

Exemple

>>> t = ['a', 'b', 'c'] >>> t[0] 'a' >>> t[1] 'b' >>> elt = t[2] >>> elt 'c'

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

Indice 0 1 2
Elément 'a' 'b' 'c'

On notera que l'indice du premier élément porte le numéro 0 et pas le numéro 1 !

Notez que le dernier indice valide est obtenu avec len(t)-1.

01° L'encodage ASCII des caractères fait correspondre un nombre à quelques caractères.

ascii = ['\x00', '\x01', '\x02', '\x03', '\x04', '\x05', '\x06', '\x07', '\x08', '\t', '\n', '\x0b', '\x0c', '\r', '\x0e', '\x0f', '\x10', '\x11', '\x12', '\x13', '\x14', '\x15', '\x16', '\x17', '\x18', '\x19', '\x1a', '\x1b', '\x1c', '\x1d', '\x1e', '\x1f', ' ', '!', '"', '#', '$', '%', '&', "'", '(', ')', '*', '+', ',', '-', '.', '/', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=', '>', '?', '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '[', '\\', ']', '^', '_', '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '{', '|', '}', '~', '\x7f']

Question :Afficher le caractère ayant l'indice 65 en utilisant le tableau ascii ci-dessous.

...CORRECTION...

1 2
ascii = ['\x00', '\x01', '\x02', '\x03', '\x04', '\x05', '\x06', '\x07', '\x08', '\t', '\n', '\x0b', '\x0c', '\r', '\x0e', '\x0f', '\x10', '\x11', '\x12', '\x13', '\x14', '\x15', '\x16', '\x17', '\x18', '\x19', '\x1a', '\x1b', '\x1c', '\x1d', '\x1e', '\x1f', ' ', '!', '"', '#', '$', '%', '&', "'", '(', ')', '*', '+', ',', '-', '.', '/', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=', '>', '?', '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '[', '\\', ']', '^', '_', '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '{', '|', '}', '~', '\x7f'] print(ascii[65])
5 - Lecture des éléments à l'aide d'une boucle et de l'indice (méthode classique) (RAPPEL)

Dans cette boucle FOR, on utilise la syntaxe in range pour obtenir successivement différentes valeurs d'indice.

Exemple avec un tableau de 14 éléments :

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

Nous avons 14 éléments mais des indices 0 à 13.

Indice 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

5.1 - Version bisounours

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

La variable de boucle i va alors prendre successivement les valeurs 0 puis 1 puis 2 ... et finalement 13.

Ce programme affiche bien le contenu des cases puisqu'on demande en ligne 4 d'afficher notes[i] et pas juste i :

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

C'est donc comme si vous aviez tapé ceci :

1 2 3 4 5 .
notes = [15, 18, 8, 10, 12, 15, 20, 5, 12, 17, 12, 10, 18, 4] print(notes[0]) print(notes[1]) print(notes[2]) ... print(notes[13])

5.2 - Version réelle

On utilisera plutôt len() pour ne pas avoir à taper directement la taille du tableau.

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

5.3 - Contenu de case ou numéro de case ?

  • La variable i contient le numéro d'une case du tableau
  • L'expression notes[i] correspond au contenu de la case i.

5.4 - Gestion du print

Si on désire voir les notes s'afficher en les séparant par un tiret, on peut utiliser ceci :

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

On obtient alors ceci

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

02° Observer attentivement ces programmes. On veut afficher le contenu des cases.

Questions

  1. Doit-on prendre le programme 1 ou le programme 2 ?
  2. Quelles sont les valeurs que va prendre la variable de boucle i ?
  3. Quel va être l'affichage ?

Programme 1

1 2 3 4
notes = [15, 18, 8] for i in range(len(notes)): print(i, end="|")

Programme 2

1 2 3 4
notes = [15, 18, 8] for i in range(len(notes)): print(notes[i], end="|")

...CORRECTION...

  1. Le programme 2 car on affiche le contenu en demandant avec notes[i].
  2. La variable i vaut d'abord 0 puis 1 puis 2 puisqu'il y a 3 cases.
  3. i vaut 0. On aura donc  0|  à l'écran.

  4. Quel va être l'affichage obtenu après deux tours de boucle ?
  5. i vaut 1. On rajoute donc 1| et on obtiendra au total  0|1| .

  6. Quel va être l'affichage final ?
  7. i vaut 2. On rajoute donc 2| et on obtiendra au total  0|1|2| .

03° Compléter la fonction maximum() qui doit renvoyer la position de la valeur maximum dans le tableau. En cas d'égalité, on devra renvoyer la première valeur maximale rencontrée.

notes = [15, 18, 8, 10, 12, 15, 18, 4]

L'appel maximum(notes) devrait renvoyer 1 sur cet exemple, car le 18 est en position 1 et 6.

1 2 3 4 5 6 7 8 9 10
def maximum(t:'list NON VIDE') -> int: """Renvoie l'indice du plus grand élément présent""" indice_du_max = ... for i in ...: if t[i] > ...: ... = ... return ... notes = [15, 18, 8, 10, 12, 15, 18, 4] print(maximum(notes))

...CORRECTION...

1 2 3 4 5 6 7
def maximum(t:'list NON VIDE') -> int: """Renvoie l'indice du plus grand élément présent""" indice_du_max = 0 for i in range(len(t)): if t[i] > t[indice_du_max]: indice_du_max = i return indice_du_max

04° Compléter la fonction progression() qui doit renvoyer le nombre de fois où une case contient une valeur plus grande que la précédente.

notes = [15, 18, 8, 10, 12, 15, 20, 4]

L'appel progression(notes) devrait renvoyer 5 : 18 plus grand que 15, et plus loin, on trouve une succession de 4 valeurs successivement plus grandes : 8-10-12-15-20.

1 2 3 4 5 6 7
def progression(t:'list NON VIDE') -> int: """Renvoie le nombre de notes plus grande que la précédente""" nb = ... for i in range(1, ...): if t[i] > t[...]: nb = ... + ... return ... notes = [15, 18, 8, 10, 12, 15, 18, 4] print(progression(notes))

...CORRECTION...

1 2 3 4 5 6 7
def progression(t:'list NON VIDE') -> int: """Renvoie le nombre de notes plus grande que la précédente""" nb = 0 for i in range(1, len(t)): if t[i] > t[i - 1]: nb = nb + 1 return nb
6 - Lecture directe des éléments un à un (NOUVEAU)

Dans cette boucle FOR, on note le nom du tableau directement derrière le in. Aucun range à l'horizon.

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 note in notes: if note > 12: print(f"Bien : {note}") elif note < 8: print(f"Pas bien : {note}") else: print(f"Moyen : {note}")

La variable de boucle note va alors contenir successivement tous les éléments du tableau notes.

note va donc valoir d'abord 15, puis 18 au tour de boucle suivant, puis 8...

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

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

05° Compléter la fonction positif_uniquement() qui doit recevoir un tableau de nombres entiers positifs ou négatifs (précondition) et qui doit afficher à l'écran uniquement les nombres s'ils sont positifs.

Cette fonction doit :

  • Lire chaque valeur v contenue dans le paramètre t.
  • Afficher (avec passage à la ligne) uniquement les notes supérieures ou égales à 0.
1 2 3 4 5 6 7 8 9
def positif_uniquement(t:list) -> None: """AFFICHE uniquement les nombres positifs contenus dans le tableau t""" for v in ...: if ...: print(...) positif_uniquement([-65, 66, -67, 68])

Vous devriez obtenir l'affichage suivant :

66 68

...CORRECTION...

1 2 3 4 5 6 7 8 9
def positif_uniquement(t:list) -> None: """AFFICHE uniquement les nombres positifs contenus dans le tableau t""" for v in t: if v >= 0: print(v) positif_uniquement([-65, 66, -67, 68])

Plus compliqué : nous allons réaliser une fonction capable d'afficher le texte correspondant à une suite de nombres encodant un texte en ASCII. Cela vous permettra de comprendre qu'un texte n'est qu'une suite de nombres pour un systme informatique.

Vous allez donc devoir lire les valeurs v contenues dans un tableau et utiliser ces valeurs comme des indices dans le tableau ascii...

06° Compléter la fonction decode() qui doit recevoir un tableau de nombres entiers positifs compris entre 0 et 127 et qui affiche le string correspondant à l'écran.

Cette fonction doit :

  • Lire chaque valeur entière code contenue dans le tableau t reçu en paramètre.
  • Afficher (sans passage à la ligne) le caractère placé à l'indice code dans le tableau ascii.
1 2 3 4 5 6 7 8 9 10 11 12
def decode(t:list) -> None: """AFFICHE les caractères ASCII correspondant aux nombres reçus dans le tableau t""" ascii = ['\x00', '\x01', '\x02', '\x03', '\x04', '\x05', '\x06', '\x07', '\x08', '\t', '\n', '\x0b', '\x0c', '\r', '\x0e', '\x0f', '\x10', '\x11', '\x12', '\x13', '\x14', '\x15', '\x16', '\x17', '\x18', '\x19', '\x1a', '\x1b', '\x1c', '\x1d', '\x1e', '\x1f', ' ', '!', '"', '#', '$', '%', '&', "'", '(', ')', '*', '+', ',', '-', '.', '/', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=', '>', '?', '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '[', '\\', ']', '^', '_', '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '{', '|', '}', '~', '\x7f'] for code in ...: print(...[...], end="") print() # passage à la ligne final. decode([65, 66, 67]) decode([66, 114, 97, 118, 111])

Vous devriez obtenir l'affichage suivant :

ABC Bravo

...CORRECTION...

1 2 3 4 5 6 7 8 9 10 11 12
def decode(t:list) -> None: """AFFICHE les caractères ASCII correspondant aux nombres reçus via le tableau t""" ascii = ['\x00', '\x01', '\x02', '\x03', '\x04', '\x05', '\x06', '\x07', '\x08', '\t', '\n', '\x0b', '\x0c', '\r', '\x0e', '\x0f', '\x10', '\x11', '\x12', '\x13', '\x14', '\x15', '\x16', '\x17', '\x18', '\x19', '\x1a', '\x1b', '\x1c', '\x1d', '\x1e', '\x1f', ' ', '!', '"', '#', '$', '%', '&', "'", '(', ')', '*', '+', ',', '-', '.', '/', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=', '>', '?', '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '[', '\\', ']', '^', '_', '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '{', '|', '}', '~', '\x7f'] for code in t: print(ascii[code], end="") print() # passage à la ligne final. decode([65, 66, 67]) decode([66, 114, 97, 118, 111])
7 - Les tableaux sont muables en Python (RAPPEL + NOUVEAU)

Dans beaucoup de langages, les tableaux sont muables : cela veut dire qu'on peut modifier les contenus d'un tableau sans modifier l'adresse-mémoire du tableau lui-même.

On dit qu'on modifie l'état du tableau lorsqu'on modifie son contenu.

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

Point important : la modification de contenu nécessite l'utilisation de l'indice. Il faut donc nécessairement passer par la version de la boucle for avec indice.

Exemple qui FONCTIONNE

Si on veut multiplier par deux toutes les notes d'un tableau (spécial ProfQuiFaitUnDsTropDur), on pourra faire ceci :

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

Après application de ce programme, le tableau notes contiendrait 

-
notes = [30, 36, 16, 20, 24, 30, 40, 10, 24, 34, 24, 20, 36, 8]

Exemple qui NE FONCTIONNE PAS

1 2 3 4
notes = [15, 18, 8, 10, 12, 15, 20, 5, 12, 17, 12, 10, 18, 4] for note in notes: note = note * 2

Après application de ce programme, le tableau notes n'aura pas été modifié !

Pourquoi ? Car en ligne 4, on modifie juste la variable locale note, pas le contenu d'une case du tableau.

8 - Une explication par l'exemple de la modification (NOUVEAU)

On considère initialement un tableau nommé t qui contient ['a', 'b', 'c']. Voici l'espace des noms et l'espace-mémoire à ce moment :

  • On voit que :
    • t ne contient pas le contenu du tableau mais son adresse (1485)
    • Le contenu de la case 0 est référencé à l'adresse 1485+0 = 1485.
    • Le contenu de la case 1 est référencé à l'adresse 1485+1 = 1486.
    • Le contenu de la case 2 est référencé à l'adresse 1485+2 = 1487.

    Si on veut voir ce que va renvoyer t[0], il suffit de voir que l'adresse du tableau est 1485 dans l'espace des noms. Puisqu'on veut la case d'indice 0, on regarde juste le contenu de la case mémoire 1485. Cela nous mène à l'adresse-mémoire 78 qui mène à 'a'.

  • Si on modifie le tableau avec t[0] = 'Z', le tableau fait toujours référence à 1485 mais la case-mémoire 1485 mène maintenant à l'adresse 170 qui contient 'Z'.
Animation du changement d'état
CLIQUER SUR L'IMAGE pour ANIMER ou STOPPER

07° Réaliser un court programme (sans fonction) pour les profs lunatiques : on transforme les notes contenues dans un tableau fourni en début de programme. Les notes initialement supérieures ou égales à 10 sont transformées en 20. Les notes inférieures à 10 sont transformées en 0.

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

Exemple AVANT / APRES :

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

...CORRECTION...

1 2 3 4 5 6 7
notes = [15, 18, 8, 10, 12, 15, 20, 5, 12, 17, 12, 10, 18, 4] for i in range(len(notes)): if notes[i] >= 10: notes[i] = 20 else: notes[i] = 0

9 - Alors, quelle boucle for ?

Ca dépend des situations.

(Cas 1) Vous voulez modifier le contenu du tableau : une seule solution

Vous avez besoin de connaître le numéro d'indice, il faut utiliser

  • for i in range(len(a)) avec
  • un accès au contenu de la case avec a[i]
  • une modification du contenu de la case avec a[i] = nouveau_contenu

Exemple : vous voulez mettre 0 dans toutes les cases (spécial Prof PasContent).

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

(Cas 2) Vous voulez lire le contenu et agir en fonction de la position du contenu : une seule solution

Vous avez besoin de connaître le numéro d'indice, il faut utiliser for i in range(len(a))

(Cas 3) : vous voulez juste lire le contenu du tableau

Puisque vous n'avez pas besoin de connaître l'indice de l'élément, vous pouvez utiliser la version que vous voulez.

  • for i in range(len(t)) avec un accès au contenu avec t[i]
  • for v in t avec un accès au contenu avec v

2 - Création de tableaux par compréhension

Jusqu'à présent, vous ne savez créer des tableaux qu'en extension : on fournit directement dans les crochets les valeurs voulues. Pour créer un tableau contenant les entiers de 1 à 3000, ca risque d'être long à taper...

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

La déclaration d'un tableau par compréhension consiste à créer un tableau à l'aide d'une boucle for. Créons un nouveau tableau nt.

nt = [None for element in base]

Comme doit-on comprendre cela ? Suivez bien ce qui suit.

  1. On voit d'abord qu'on déclare un nouveau tableau nt :
  2. nt = [...]

  3. Cette déclaration contient une boucle, il s'agit d'une déclaration par compréhension :
  4. nt = [... for element in base]

    Il faut comprendre que pour chaque element lu dans le tableau base, il faut faire quelque chose.

  5. Faire quoi ? Rajouter une nouvelle case à notre nouveau tableau. Case qui contient quoi ? Ce qui se trouve devant le for.
  6. nt = [None for element in base]

    En tapant ceci, voici ce que peut comprendre l'interpréteur Python : "Crée un nouveau tableau initialement vide nommé nt. Pour chaque case du tableau base, crée une case contenant None dans nt.

Exemple 1

>>> base = [1, 2, 5] >>> nt = [None for valeur in base] >>> nt [None, None, None]

On obtient bien un nouveau tableau ayant autant de cases mais rempli de None.

Exemple 2

On peut mettre autre chose que None dans chaque case : on peut indiquer un calcul expliquant ce que doit être le contenu de la nouvelle case.

dd = [v * 2 for v in b]

L'interpréteur Python comprend qu'on veut créer un nouveau tableau dd où chaque case correspond au double de ce qui est contenu dans la case correspondante du tableau b.

>>> b = [1, 2, 5] >>> dd = [v*2 for v in b] >>> dd [2, 4, 10]

08° Créer, par compréhension, un tableau qui contient des valeurs 100 fois plus grandes que le tableau suivant :

>>> t1 = [1, 2, 3, 5, 7, 11]

...CORRECTION...

>>> t1 = [1, 2, 3, 5, 7, 11] >>> dd = [v*100 for v in t1] >>> dd [100, 200, 300, 500, 700, 1100]

09° Créer, par compréhension, un tableau longueurs dont les cases contiennent le nombre de lettres des prénoms contenus dans le tableau prenoms :

>>> prenoms = ["Lisa", "Scott", "Matthias", "Antoine", "Ethan", "Lucas", "Manon", "Alexandre", "Alexandre", "Kenzo", "Thomas", "Lilou", "Aurélien", "Charles", "Manon", "Francia", "Imrane", "Sarah", "Yassin", "Sofian", "Noé", "Lenny", "Matt", "Ryiad", "Yanis", "Jason", "Damien", "Antonin", "Samy", "Laurine", "Rayan", "Eliot", "Victor", "Theo", "Julien", "Benjamin"]

Vous devriez pouvoir visualiser ceci dans la console après exécution de votre création par compréhension :

>>> longueurs [4, 5, 8, 7, 5, 5, 5, 9, 9, 5, 6, 5, 8, 7, 5, 7, 6, 5, 6, 6, 3, 5, 4, 5, 5, 5, 6, 7, 4, 7, 5, 5, 6, 4, 6, 8]

...CORRECTION...

>>> prenoms = ["Lisa", "Scott", "Matthias", "Antoine", "Ethan", "Lucas", "Manon", "Alexandre", "Alexandre", "Kenzo", "Thomas", "Lilou", "Aurélien", "Charles", "Manon", "Francia", "Imrane", "Sarah", "Yassin", "Sofian", "Noé", "Lenny", "Matt", "Ryiad", "Yanis", "Jason", "Damien", "Antonin", "Samy", "Laurine", "Rayan", "Eliot", "Victor", "Theo", "Julien", "Benjamin"] >>> longueurs = [len(p) for p in prenoms] >>> longueurs [4, 5, 8, 7, 5, 5, 5, 9, 9, 5, 6, 5, 8, 7, 5, 7, 6, 5, 6, 6, 3, 5, 4, 5, 5, 5, 6, 7, 4, 7, 5, 5, 6, 4, 6, 8]
11 - Déclaration de tableau par compréhension avec indice

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

Exemple 1

>>> t = [0 for i in range(10)] >>> t [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]

Cela veut dire qu'on place 0 dans une case pour chaque des valeurs i (qui vaut 0 puis 1 puis 2 ... jusqu'à 9)

Exemple 2

>>> t = [i*10 for i in range(10)] >>> t [0, 10, 20, 30, 40, 50, 60, 70, 80, 90]

Cette fois, la variable de boucle i va varier de 0 à 9 et pour chacune des valeurs qu'elle prend, on place 10 fois plus dans une nouvelle case du nouveau tableau.

Exemple 3

>>> import random >>> tableau = [random.randint(1, 100) for x in range(10)] >>> tableau [42, 41, 96, 35, 58, 94, 16, 21, 84, 51]

Cette fois, on crée 10 cases dans lesquelles on place un nombre aléatoire entre 1 et 100.

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

...CORRECTION...

>>> import random >>> tableau = [random.randint(2, 50) for x in range(100)]

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

...CORRECTION...

>>> tableau = [0 for _ in range(500)]

On peut même faire mieux : on peut inclure une instructions conditionnelles ou même un appel de fonction dans la construction.

12 - Déclaration par compréhension avec condition

Premier exemple de construction par compréhension : avec condition d'ajout :

On crée un tableau de 50 notes comprises entre 0 et 20. On crée un second tableau à partir du premier : on ne garde que les notes supérieures ou égales à 10.

>>> import random >>> t = [random.randint(0,20) for i in range(50)] >>> 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 = [note for note in t if note >= 10] >>> 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]

Deuxième exemple de construction par compréhension : avec fonction :

On peut utiliser des fonctions pour déterminer la valeur à placer lors de la création par compréhension. Imaginons qu'on dispose de cette fonction en mémoire :

1 2 3 4 5
def pas_plus(valeur, seuil): """Fonction qui écrête : elle renvoie la valeur ou le seuil si la valeur est supérieure au seuil""" if valeur > seuil: return seuil return valeur
>>> import random >>> tableau = [pas_plus(random.randint(0,20), 15) for valeur in range(10)] >>> tableau [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.

12° Créer un tableau p6 dont les cases contiennent les prénoms de 6 caractères ou plus contenus dans le tableau prenoms :

>>> prenoms = ["Lisa", "Scott", "Matthias", "Antoine", "Ethan", "Lucas", "Manon", "Alexandre", "Alexandre", "Kenzo", "Thomas", "Lilou", "Aurélien", "Charles", "Manon", "Francia", "Imrane", "Sarah", "Yassin", "Sofian", "Noé", "Lenny", "Matt", "Ryiad", "Yanis", "Jason", "Damien", "Antonin", "Samy", "Laurine", "Rayan", "Eliot", "Victor", "Theo", "Julien", "Benjamin"]

Vous devriez pouvoir visualiser ceci dans la console après exécution de votre création par compréhension :

>>> p6 ['Matthias', 'Antoine', 'Alexandre', 'Alexandre', 'Thomas', 'Aurélien', 'Charles', 'Francia', 'Imrane', 'Yassin', 'Sofian', 'Damien', 'Antonin', 'Laurine', 'Victor', 'Julien', 'Benjamin']

...CORRECTION...

>>> prenoms = ["Lisa", "Scott", "Matthias", "Antoine", "Ethan", "Lucas", "Manon", "Alexandre", "Alexandre", "Kenzo", "Thomas", "Lilou", "Aurélien", "Charles", "Manon", "Francia", "Imrane", "Sarah", "Yassin", "Sofian", "Noé", "Lenny", "Matt", "Ryiad", "Yanis", "Jason", "Damien", "Antonin", "Samy", "Laurine", "Rayan", "Eliot", "Victor", "Theo", "Julien", "Benjamin"] >>> p6 = [p for p in prenoms if len(p) >= 6] >>> p6 ['Matthias', 'Antoine', 'Alexandre', 'Alexandre', 'Thomas', 'Aurélien', 'Charles', 'Francia', 'Imrane', 'Yassin', 'Sofian', 'Damien', 'Antonin', 'Laurine', 'Victor', 'Julien', 'Benjamin']
13 - Tableau statique ou list-Python ?

Nous avons travaillé ici avec la notion de tableaux statiques : des tableaux dont

  1. toutes les cases contiennent le même type de données et
  2. le nombre de cases est fixe. Pas moyen d'en supprimer ou d'en rajouter. Si le tableau a 20 cases, il gardera 20 cases jusqu'à la fin.

Les tableaux statiques s'implémentent en Python à l'aide du type list.

Pour informations, sachez qu'une list Python est bien plus flexible qu'un tableau statique. Il s'agit d'un tableau dynamique (on peut ajouter ou supprrimer des cases) donc le contenu n'a pas à être homogène.

La plupart du temps, nous utiliserons une List-Python comme un tableau statique, sans chercher à profiter des fonctionnalités ci-dessous.

On pourrait donc créer une list Python contenant ceci :

exemple = [1, 1.55, 'bonjour']

Mais dans ce cas, nous ne dirons pas que la variable exemple fait référence à un tableau.

Nous verrons en fin d'année et en terminale, comme rajouter une case derrière les autres avec append() ou supprimer la dernière case avec pop(). Juste un petit exemple pour vous montrer comment cela s'utilise en attendant :

  • append() ne renvoie rien mais modifie le tableau en mémoire en rajoutant l'élément fourni en tant que dernière case.
  • pop() modifie le tableau en mémoire en supprimant sa case finale et renvoie l'élément qui y était contenu.
>>> t = [] >>> t.append("Alice") >>> t ['Alice'] >>> t.append("Bob") >>> t ['Alice', 'Bob'] >>> t.append("Charlie") >>> t ['Alice', 'Bob', 'Charlie'] >>> t.pop() 'Charlie' >>> t ['Alice', 'Bob']

Attention : pas de telle utilisation des Lists pour l'instant.

3 - Alias et copie

Nous avons vu qu'une variable faisant référence à un tableau ne contient pas le contenu du tableau mais simplement son identifiant-mémoire, la zone où les données sont référencées.

Et comme le tableau est muable en Python, on peut modifier son contenu si on connaît cette adresse.

14 - Alias de tableau

Une "variable-tableau" contient l'identifiant de la zone-mémoire où se trouve le premier contenu, celui de l'indice 0. On trouve facilement les autres en augmentant ensuite de 1.

Exemple :

  • t fait référence à l'adresse 5000.
  • L'adresse 5000 contient l'adresse faisant référence à t[0].
  • L'adresse 5001 contient l'adresse faisant référence à t[1].
  • L'adresse 5002 contient l'adresse faisant référence à t[2].
  • ...

On crée facilement un alias d'un tableau en notant une instruction de ce type :

>>> t = [10, 20, 50] >>> id(t) xxxx128 >>> t2 = t >>> id(t2) xxxx128

On voit clairement que t et t2 référencent la même zone-mémoire. Du coup, si on modifie le contenu de l'un, on modifie le contenu de l'autre puisqu'il s'agit de la même zone-mémoire.

Sur l'exemple, t et t2 sont deux façons de nommer la zone-mémoire 128.

>>> t [10, 20, 50] >>> t2 [10, 20, 50] >>> t[0] = 100000 >>> t [100000, 20, 50] >>> t2 [100000, 20, 50]

C'est comme appelé quelqu'un par son vrai nom ou par son surnom. Ca ne change rien à la personne designée.

13° Donner le contenu de t à la fin des instructions suivantes :

>>> t = [i*10 for i in range(4)] >>> a = t >>> b = a >>> c = b >>> a[2] = a[2]*2 >>> t ???

...CORRECTION...

Hyper facile lorsqu'on a compris.

On crée t par compréhension. i prendra les valeurs 0, 1, 2, 3.

Le tableau t fait donc référence à un contenu qui correspond à [0, 10, 20, 30].

a, b, c ont en réalité la même référence mémoire que t, un tableau muable.

L'instruction a[2] = a[2]*2 se comprend en l'analysant de droite à gauche. On évalue d'abord a[2] et on obtient 20. On double et on obtient 40. On stocke ce 40 dans la case d'indice 2 du tableau a.

Mais puisque les 4 variables sont des alias de la même zone mémoire, on a alors :

a = b = c = t = [0, 10, 40, 30]

15 - Copie de tableau

Pour éviter ces modifications d'un tableau sur l'autre, il faut créer une copie du tableau de base et pas juste en faire un alias.

1er méthode : copie par compréhension (à privilégier en NSI)

>>> t = [0, 10, 20, 30] >>> t2 = [v for v in t] >>> t [0, 10, 20, 30] >>> t2 [0, 10, 20, 30] >>> t[0] = 1000 >>> t [1000, 10, 20, 30] >>> t2 [0, 10, 20, 30] >>> t2[3] = 3000 >>> t [1000, 10, 20, 30] >>> t2 [0, 10, 20, 3000]

Cette fois, t et t2 sont bien des contenus similaires au début mais on peut les modifier l'un ou l'autre sans impacter l'autre. Ce sont des copies d'un même contenu et pas des alias d'une même zone mémoire.

Important : Cela ne fonctionnera pas si le premier tableau contient des éléments muables (d'autres tableaux par exemple). Dans ce cas, il faudra faire une copie dite profonde.

2e méthode : copie en utilisant la méthode des list nommée copy()

>>> t = [0, 10, 20, 30] >>> t2 = t.copy()

On obtient à ce moment, deux tableaux identiques mais indépendants l'un par rapport à l'autre.

>>> t [0, 10, 20, 30] >>> t2 [0, 10, 20, 30] >>> t[0] = 1000 >>> t [1000, 10, 20, 30] >>> t2 [0, 10, 20, 30] >>> t2[3] = 3000 >>> t [1000, 10, 20, 30] >>> t2 [0, 10, 20, 3000]

Important : Cela ne fonctionnera pas si le premier tableau contient des éléments muables (d'autres tableaux par exemple). Dans ce cas, il faudra faire une copie dite profonde.

Si votre tableau contient d'autres tableaux, il faut donc en faire une copie profonde. Le plus facile pour être certain de n'avoir aucun alias d'une autre zone mémoire est d'utiliser la fonction deepcopy() du module nommé copy. Nous en reparlerons lorsque le besoin s'en fera sentir.

14° Donner le contenu de t à la fin des instructions suivantes :

>>> t = [i*10 for i in range(4)] >>> a = t >>> b = a >>> c = [v for v in b] >>> c[2] = c[2]*2 >>> t ???

...CORRECTION...

Hyper facile lorsqu'on a compris.

On crée t par compréhension. i prendra les valeurs 0, 1, 2, 3.

Le tableau t fait donc référence à un contenu qui correspond à [0, 10, 20, 30].

a, b ont en réalité la même référence mémoire que t, un tableau muable.

Par contre, c est une copie du contenu-mémoire référencé par b et donc t également.

On crée c par compréhension en demandant de créer un tableau qui contient une case ayant le même contenu que celle de t, pour chaque valeur de t.

Modifier c ne va donc pas modifier du tout t.

4 - Raccourcis

Il y a encore beaucoup à dire sur les tableaux.

Vous vous doutez bien par contre que la plupart des actions ou recherches usuelles qu'on peut faire sur les tableaux sont déjà implémentées en Python.

Le but de la NSI n'est pas de vous faire utiliser ces fonctions mais de vous permettre de les créer pour comprendre comment elles sont implémenter et donc comprendre leurs coûts.

Vous allez ainsi voir dans la partie algorithmique :

  • Comment réaliser une recherche de minimum, de maximum ou de somme des éléments d'un tableau autrement qu'en passant par ces fonctions natives forts pratiques. Vous pouvez les utiliser en NSI si leurs utilisations ne sont pas le ressort principal de la question qu'on vous pose.
  • >>> t = [10, 30, 25, -5] >>> min(t) -5 >>> max(t) 30 >>> sum(t) 60
  • Comment vérifier l'appertenance d'un élément : cet élément est-il dans le tableau ?
  • >>> t = [10, 30, 25, -5] >>> 30 in t True >>> 29 in t False
  • Comment trier une copie triée d'un tableau ?
  • >>> t = [10, 30, 25, -5] >>> t2 = sorted(t) >>> t [10, 30, 25, -5] >>> t2 [-5, 10, 25, 30]
  • Comment obtenir la moyenne issue d'un tableau de nombres ?
  • >>> t = [10, 30, 25, -5] >>> m = sum(t) / len(t) 15.0

15° Utiliser les exemples précédents pour vous convaincre qu'ils fonctionnent correctement.

16° Pendant une épreuve de programmationn on vous demande de créer une fonction qui renvoie le maximum des valeurs d'un tableau, un élève peut-il rendre ceci et espérer avec des points ?

1 2
def maximum(t): return max(t)

...CORRECTION...

J'espère que vous avez bien compris qu'il aurait 0.

Par contre, pour vos propres projets, c'est pratique, n'hésitez pas.

5 -

6 - FAQ

Rien pour l'instant

Nous avons vu  

  • Les fonctions
  • Les instructions conditionnelles if elif else
  • Les boucles bornées for
  • Les boucles non bornées while
  • strings et tableaux

Des informations supplémentaires dans la partie FICHES, dont

Activité publiée le 01 11 2019
Dernière modification : 07 09 2024
Auteur : ows. h.