Tableaux et tuples
On l'a vu, Python propose 4 types de données de base ( pour rappel : int, float, str et bool ).
A partir de là, il est possible de "construire" ses propres types de données à partir des précédents.
Prenons un exemple : on voudrait stocker dans un script l'ensemble des notes des élèves d'une classe; il faut donc autant de variables qu'il y a de notes, et ce pour chacun des élèves :
Pour un seul élève, ça va encore...
Ensuite, ça ne devient plus gérable...
Il serait alors judicieux de regrouper les notes d'un même élève dans un même ensemble, correspondant à un nouveau type de données appelé par exemple notes; chaque élève correspondrait alors à une "variable"
différente de ce nouveau type, mais au contraire des types de base, elles stockeraient plusieurs données à la fois, regroupées sous le même nom :
Le type notes
Plusieurs variables du type notes
Un nouveau type de donnée, construit à partir d'autres types...
C'est ce que permettent de faire les p-uplet ( 1-uplet, 2-uplet, 3-uplet..., p étant le nombre d'éléments stocké(s) ) et les tableaux.
Ils correspondent en informatique à un ensemble de données ( une "collection" ), rassemblées de façon à pouvoir y accéder facilement. Chaque donnée correspond à un élément différent de l'ensemble.
Dans de nombreux langages, ces éléments doivent être du même type, mais ce n'est pas le cas en Python : on peut mettre dans un p-uplet ou un tableau Python des données de type différent, mais c'est à éviter
pour des raisons de lisibilité.
Chaque élément d'un tuple ou tableau correspond donc à une "case" dans laquelle on placerait une donnée. L'ordre dans lequel les données sont rangées permettra alors de les retrouver en désignant la bonne "case" dans laquelle elle est contenue.
| 45 | 3.2 | 27.246 | 'truc' | 78 | 'bidule' | 423 | 785 | 2.3 | 7.896 | True | ... |
En Python, les p-uplet sont implémentés avec le type tuple.
Les tableaux sont eux implémentés à l'aide du type de données list, appelé liste Python, mais il s'agit d'un nom qui peut prêter à confusion, car une "liste" en informatique correspond
à un concept bien différent du tableau ( concept que vous verrez d’ailleurs en Terminale si vous continuez la spécialité NSI ).
Il y a des raisons pour que les concepteurs du langage Python aient quand même choisi le nom "liste" pour désigner les tableaux, mais nous ne nous étendrons pas là-dessus.
Nous utiliserons dorénavant toujours le mot "tableau" pour désigner ce type de données, mais ne vous étonnez pas de trouver le mot "liste" dans d'autres cours ou sur Internet.
La grosse différence entre tuple et tableau est la suivante :
- un tuple, et les éléments d'un tuple, ne peuvent pas être modifiés après création : un tuple est un objet immuable ( = non-mutable ).
Les données dans un tuple sont représentées placées entre parenthèses, séparées par des virgules :(1, 6, 8, 11). - les tableaux, et les éléments qu'ils contiennent, peuvent au contraire être modifiés : un tableau est un objet mutable.
Les données dans tableau sont représentées placées entre crochets, séparées par des virgules :[1, 6, 8, 11].
Un tableau ou un tuple a un nom : ce nom est commun à l'ensemble des données stockées dans le tuple ou le tableau; on le choisit arbitrairement, mais comme pour les variables, il y a certaines restrictions dans ce choix : on ne peut pas utiliser
les termes du langage Python lui-même, le nom ne doit pas commencer par un chiffre ni un caractère autre qu'une lettre, il ne doit pas y avoir d'espace,...
On peut utiliser des lettres majuscules, sauf au début du nom.
Initialisation/création d'un tuple ou d'un tableau
Création par instanciation ( "de toute pièce" )
C'est la seule méthode pour créer un tuple. On décrit l'ensemble des éléments, séparés par des virgules; la syntaxe change pour les tuples et les tableaux :
tableau1 = [45, 32, 27, 189, 78, 569, 423, 785, 23, 78, 630] # utilisation de crochets pour les tableaux
noms = ('durand', 'martin', 'roger', 'paul', 'dubois', 'jean') # utilisation de parenthèses pour les tuples
Pour les tableaux uniquement
Création d'un tableau vide
Vous aurez parfois besoin d'initialiser un tableau vide, c'est à dire n'ayant aucun élément :
tableau_vide = []
"Remplissage automatique"
Pour remplir automatiquement un tableau avec un nombre donné d'éléments tous identiques :
tableau1 = [None]*100 # crée un tableau contenant 100 éléments tous égaux à None ( = "rien" )
tableau2 = [0]*10 # crée un tableau contenant 10 éléments tous égaux à 0
( Vous aviez déjà vu cette façon de faire avec les chaînes de caractères...)
Création à l'aide d'une boucle
Méthode 1
La première idée est de créer un tableau ayant un certain nombre d'éléments de valeur quelconque dans un premier temps ( None par exemple, qui signifie "rien" ), et de "remplir" ensuite chaque "case" avec une valeur :
tab = [None]*10 # création d'un tableau de 10 éléments tous égaux à 'None'
for i in range(10):
tab[i] = 2**i # "remplit" chaque élément avec une puissance croissante de 2
print(tab)
[1, 2, 4, 8, 16, 32, 64, 128, 256, 512]
Méthode 2
A partir d'un tableau ne contenant initialement aucun élément ( = tableau vide ), on "ajoute" les éléments les uns après les autres à la fin du tableau qui se construit donc petit à petit; pour
cela, on utilise une méthode particulière associée aux listes Python, la méthode append :
tab = [] # tableau vide
for i in range(10):
tab.append(2**i) # "append" = "ajouter à la fin"
Il existe une autre syntaxe, équivalente à la précédente : :
tab = []
for i in range(10):
tab = tab + [2**i]
Mais vous verrez en Terminale qu'elle est moins efficace que la précédente : on préférera donc utiliser la méthode append.
Les tableaux par compréhension
Attention, méthode très puissante, mais pas évidente à maîtriser. Mais elle est au programme et sera dorénavant très utilisée !
C'est une méthode de création de tableau équivalente aux deux précédentes, mais en beaucoup plus concis :
tableau1 = [i for i in range(10)] # crée un tableau contenant 10 éléments de 0 à 9
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>>
tableau2 = [2*i for i in range(10)] # crée un tableau contenant 10 éléments, chaque élément étant le double du compteur i
[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
>>>
tableau3 = [2*i for i in range(10) if i%3 == 0 ] # crée un tableau contenant les éléments double du compteur i, mais uniquement si i est divisible par 3
[0, 6, 12, 18]
>>>
L'expression peut être plus ou moins complexe selon ce que l'on veut faire ! On peut même y mettre des conditions complexes, des boucles imbriquées, etc...
Manipulation des tuples et des tableaux
Repérage d'un élément
Chaque élément d'un tuple ou d'un tableau est repéré par son indice ( ou index ), qui représente la position de la donnée stockée ( en gros, le numéro de la "case" où la donnée est stockée ) depuis le début du tuple ou tableau.
Attention : comme beaucoup de choses en informatique ( comme par exemple les chaînes de caractères ), la numérotation des indices commence non pas à 1 mais à 0 : la première donnée a l'indice 0, la deuxième l'indice 1, la troisième 2, etc....
| Indice | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
|---|---|---|---|---|---|---|---|---|---|---|---|
| Valeur | 45 | 3.2 | 27.246 | 45.6 | 78 | 12 | 423 | 785 | 2.3 | 7.896 | 5 |
Pour adresser un élément particulier du tuple/tableau, on utilise alors la syntaxe suivante :
nom_du_tableau[indice_de_l_element]
...qui désigne alors la valeur stockée dans l'élément adressé.
Bien entendu, il faut que l'indice soit bien dans les limites "permises" du tableau, c'est à dire être compris entre 0 ( indice du premier élément ) et n - 1 ( n = nombre d'éléments du tableau ).
--------------------------------------------- | indices | 0 | 1 | 2 | 3 | ... | n-2 | n-1 | --------------------------------------------- | valeurs | . | . | . | . | ... | . | . | ---------------------------------------------
Dans le cas où l'on "sort" du tableau, Python signale une erreur IndexError : Index out of range ( que vous rencontrerez de trop nombreuses fois !! )
Exemples pour le tuple/tableau ci-dessus, nommé tup_tab :
tup_tab[0] == 45
tup_tab[3] == 45.6
tup_tab[8] == 2.3
tup_tab[12] → IndexError !
C'est donc tout à fait le même "mode de fonctionnement" que les chaînes de caractères...
Attention, une erreur classique est de confondre l'indice d'un élément dans le tuple ou le tableau, et la valeur stockée dans cet élément.
Pour simplifier :
- un élément = une "case" dans un tuple ou un tableau
- l'indice d'un élément = le numéro de la "case"
- la valeur = le contenu de la "case"
Affichage
Pour afficher un élément d'un tuple/tableau, utiliser la syntaxe précédente :
>>> print(tup_tab[8])
2.3
>>> print(tup_tab[3])
45.6
Pour afficher le tuple/tableau complet, utiliser son nom général :
>>> print(tup_tab)
[45, 3.2, 27.246, 45.6, 78, 12, 423, 785, 2.3, 7.896, 5] # ou (45, 3.2, 27.246, 45.6, 78, 12, 423, 785, 2.3, 7.896, 5) si c'est un tuple !
Nombre d'éléments dans un tuple ou un tableau
Pour trouver le nombre d'éléments présents dans un tuple ou un tableau, utiliser l'instruction len() :
>>> print(len(tup_tab))
11
Modification d'un élément
Comme on l'a dit plus haut, cela n'est possible qu'avec les tableaux et pas les tuples.
Jusqu'à maintenant, vous avez vu des types de données ( int, float, str,...et maintenant tuple ) qui sont immuables : cela
signifie que les variables de ces types ne peuvent pas être modifiées; la seule façon de les "réutiliser" est en fait de leur
réaffecter une nouvelle valeur, ce qui se traduit en réalité par la création d'une nouvelle variable portant le même nom, "l'ancienne" étant effacée de la mémoire :
Pour visualiser cela, nous allons utiliser la fonction Python id(variable), renvoyant l'identifiant unique d'une variable, qui est différent pour des variables différentes :
Les tableaux sont eux au contraire muables ( mutable en anglais ) : cela signifie que l'on peut en modifier un élément sans avoir à complètement réaffecter au tableau de nouvelles données :
On dit dans ce cas que l'on modifie un tableau par mutation ( et donc pas par réaffectation ); dans ce cas, Python n'a alors pas besoin de créer une nouvelle variable.
Bien entendu, rien n'empêche cependant de réaffecter à une variable un tableau complètement nouveau !
Ce mode de fonctionnement est bien pratique, mais peut entraîner des problèmes, par exemple lors de la copie d'un tableau, problèmes que nous évoquerons plus tard.
Concaténation de deux tableaux
On rappelle que concaténer signifie "ajouter à la suite de".
Comme pour les chaînes de caractère, l'opérateur + permet de concaténer deux tableaux en un plus grand :
tableau1 = [1 , 2 , 3]
tableau2 = [4 , 5 , 6]
tableau1 = tableau1 + tableau2 # on pourrait si on voulait créer aussi un troisième tableau
print(tableau1)
[1 , 2 , 3 , 4 , 5 , 6]
Autres fonctions sur les tuples et les tableaux
Détermination de l'indice d'un élément donné
Pour déterminer l'indice d'une valeur particulière dans un tuple ou un tableau ( ça peut servir...), utiliser la fonction index() :
>>>tableau4 = ['lundi','mardi','mercredi','jeudi','vendredi','samedi','dimanche']
>>> print(tableau4.index('mercredi'))
2
Attention si il y a des doublons : la fonction méthode() ne donne que l'indice du premier élément rencontré ayant la valeur recherchée.
Si la valeur cherchée n'est pas dans le tableau, une erreur est renvoyée.
Test d'appartenance d'une valeur
On peut tester la présence de telle ou telle valeur dans un tuple ou un tableau en utilisant l'opérateur in :
if 45 in tup_tab : # renvoie True
print("Valeur présente")
if 214 in tup_tab : # renvoie False
print("Valeur absente")
Tuple ou tableau ?
Quand utiliser un tuple ou un tableau ?
Vous venez de voir que les tableaux sont bien plus "souples" que les tuples, et vous en viendrez alors vite à vous demander quel est l'intérêt de ces derniers : pourquoi ne pas toujours utiliser des tableaux ?
Il faut bien voir que leur stockage en mémoire n'est pas du tout le même :
- un tuple n'étant pas modifiable, la place qu'il occupe en mémoire est bien définie et réduite au nécessaire; le parcours de ses éléments est très rapide.
- un tableau peut être modifié, voire rallongé, diminué..., Python est obligé de réserver pour lui en mémoire plus de place que nécessaire pour anticiper ces modifications. De plus, le parcours des éléments d'un tableau est beaucoup plus lent.
On aura donc intérêt à utiliser les tuples quand on n'aura à stocker que des données constantes au cours d'un programme.
Les tuples dans les fonctions
Les tuples sont également mis en œuvre lorsqu'une fonction doit renvoyer plusieurs résultats.
Voila par exemple la définition d'une fonction qui calcule et renvoie le quotient et le reste de la division entière de deux entiers :
def division_entiere(n1:int, n2:int) -> int:
quotient = n1 // n2
reste = n1 % n2
return quotient, reste # renvoi des deux valeurs sous forme d'un tuple ( les parenthèses sont optionnelles dans cette situation )
Les deux résultats quotient et reste sont renvoyés sous forme d'un tuple au programme principal.
Il faudra donc penser que le type de la variable utilisée lors de l'appel de la fonction depuis le programme principal sera un tuple :
resultat = division_entiere(146, 78) # affectation du résultat renvoyé par la fonction au tuple 'resultat'
print("Le quotient est égal à", resultat[0])
print("Le reste est égal à", resultat[1])
On peut également récupérer les deux résultats du tuple...directement dans un tuple de deux éléments :
quotient, reste = division_entiere(146, 78) # affectation du résultat renvoyé au tuple (quotient, reste) ( là non plus, les parenthèses ne sont pas obligatoires )
# bien entendu, les éléments de ce tuple doivent être dans le même ordre que celui de la fonction !
print("Le quotient est égal à", quotient)
print("Le reste est égal à", reste)
Vous rencontrerez assez souvent des fonctions renvoyant des tuples de plusieurs résultats, faites attention quand c'est le cas !
QCM d'entraînement
Exercices
Manipulation de base sur les tableaux
Définir le tableau [17, 38, 10, 25, 72] en lui donnant un nom, puis effectuez les actions suivantes :
- afficher le tableau complet
- afficher le troisième élément du tableau ( '10' ).
- afficher l’indice de l’élément '25' ( = 3 )
- modifier l’élément '38' et afficher le tableau
- créer un nouveau tableau qui contient 3 fois les éléments du tableau précédent dans le même ordre, puis l'afficher
- afficher le nombre d'élément de ce nouveau tableau
Création de tableaux
Créer à l'aide d'une boucle , puis afficher les tableaux suivants :
- un tableau contenant 10 zéros
- un tableau contenant les nombres pairs de 0 à 50, un autre contenant les nombres impairs de 1 à 51.
On rappelle qu'un nombre est pair si le reste de sa division par 2 est égal à 0. - un tableau contenant 10 entiers aléatoires de valeur comprise entre 1 et 100. ( utiliser la fonction
randint(a,b)du modulerandom). - un tableau de 20 nombres alternant entre 0 et 1 (
[0, 1, 0, 1, 0, ...]).
Vous utiliserez pour cela la parité de l’indice de la boucle ( la variable i de l’instructionfor i in range(...)) - un tableau de 100 nombres alternant entre −1 et 1 (
[1, -1, 1, -1, 1, ...]). Vous pourrez utiliser astucieusement l’indice de la boucle... mais il existe de nombreuses autres approches ! - un tableau contenant les résultats de la table de multiplication de 7, en allant de 7 x 0 à 7 x 12.
Création de tableaux par compréhension
Reprendre les exercices précédents mais en utilisant cette fois la méthode de création par compréhension.
Il existe en Python l'équivalent de "l'opérateur ternaire" de certains langages, c'est à dire une expression qui est évaluée à un résultat différent selon qu'une condition soit vraie ou fausse :
truc if condition else machin
Cette expression est évaluée à :
- truc si la condition est vraie
- machin si elle est fausse
Cet opérateur pourra être utile dans la création par compréhension de certains tableaux.
Applications
Les tableaux et les tuples sont des types de données, ils peuvent donc très bien être utilisés comme paramètre/argument de fonction, ou alors de résultat renvoyé par une fonction.
Moyenne annuelle
- Compléter la fonction
moyenne_annuelleci-dessous qui prend en paramètre un tuple de trois nombres flottants compris entre 0 et 20 et renvoie la moyenne de ces trois nombres. - Écrire la docstring de cette fonction.
- Effectuer le jeu de tests suivant :
moyenne_annuelle((12, 13, 14)) == 13moyenne_annuelle((8, 13, 14)) == 11.666666666666666moyenne_annuelle((0, 5, 16)) == 7moyenne_annuelle((12.54, 13.12, 14.58)) == 13.413333333333332moyenne_annuelle((12.99, 17.21, 15.84)) == 15.34666666666667
Le cadavre exquis
Le cadavre exquis est un « jeu qui consiste à faire composer une phrase, ou un dessin, par plusieurs personnes sans qu'aucune d'elles ne puisse tenir compte de la collaboration ou des collaborations précédentes.»
La méthode randint(a, b) du module random permet de tirer un nombre entier au hasard entre deux bornes a et b incluses.
A vous de réfléchir ici à comment l’utiliser pour "tirer" au hasard un élément dans un tableau : quelles sont les bornes a et b à indiquer ?
- Compléter la fonction
cadavre_exquisci-dessous qui prend en paramètres :- un tableau de noms non vide,
- un tableau de verbes non vide,
- un tableau de compléments non vide,
- Utiliser la fonction avec les 3 tableaux ci-dessous.
Lancer de dés
Dans cet exercice, une fonction doit créer un tableau et le renvoyer.
Pour la création du tableau, choisir la méthode que vous préférez !! ( n'oubliez pas qu'il faut toutes les connaître..)
On lance successivement cinq dés à six faces et on souhaite mémoriser les résultats obtenus dans un tableau.
- Compléter la fonction
lancer_cinq_desci-dessous afin qu'elle renvoie un tableau contenant les résultats aléatoires de cinq lancers de dés.. - Compléter la fonction
lancer_n_desqui prend en paramètre un nombre entier positif n et renvoie un tableau de longueur n correspondant au résultat d'un lancer de n dés. Pour cela, on adaptera la fonction précédente.
La date parlante
Écrire une fonction qui prend comme paramètre une date sous la forme jj//mm/aaaa ( par exemple : 19/11/2024 ), et qui renvoie cette date sous une forme plus "parlante", comme :
19 novembre 2024.
Il existe une méthode en Python, la méthode split, qui sépare les mots d'une chaîne de caractères, selon un caractère de séparation que l'on peut éventuellement préciser
( par défaut, c'est l'espace ), et qui renvoie le tableau de ces mots :
"salut les amis".split() # le caractère de séparation est éventuellement passé en argument
>>> ["salut", "les", "amis"]
On pourra utiliser avec profit un tuple pour stocker les noms des différents mois, et s'en servir pour faire la "conversion" :
mois = ("janvier", "février", "mars", "avril", "mai", "juin", "juillet", "août", "septembre", "octobre", "novembre", "décembre")
Tester la fonction avec plusieurs dates.
Ballade dans un tableau...
On souhaite écrire un programme, qui détermine les deux valeurs, dans un tableau de valeurs entières et uniques dans le tableau, dont la somme est égale à un total donné.
Par exemple, dans le tableau : [2, 6, 5, 3, 8], les deux valeurs dont la somme est égale à 9 sont : 6 + 3 = 9.
Le principe est le suivant :
- on trie le tableau des valeurs par ordre croissant,
- on initialise une variable gauche au premier indice du tableau, et une variable droite au dernier indice.
- tant que la somme des valeurs aux indices gauche et droite n'est pas égale au total recherché :
- si la somme est plus grande que le total, on décrémente la variable droite,
- sinon, si la somme est plus petite, on incrémente la variable gauche.
- en fin de boucle, les variables gauche et droite contiennent les indices des éléments dans le tableau dont la somme des valeurs est égale au total recherché.
- sur papier, appliquer l'algorithme décrit ci-dessus, pour trouver les deux valeurs dans le tableau
[1, 3, 4, 6, 7, 8, 10, 11, 13, 17, 18, 23, 24, 30, 38, 39, 41, 50], dont la somme est égale à 46. - Compléter la fonction
somme_totalci-dessous, qui prend comme paramètres un tableau tab de valeurs entières et triées, et une valeur entière total, et renvoie les indices gauche et droite des éléments dans tab dont la somme est égale à total. - Tester la fonction !