Aller au contenu

Liste et autres types séquences

Chapitre en cours de relecture

Ce chapitre manque quelques exercices et corrections mineures. Vous pouvez vous y attaquer, mais il faudra y revenir plus tard quand les exercices auront étés ajoutés.

Ce chapitre est également trop détaillé, il doit subir une réécriture.

Le but d'un programme est en général de manipuler des données multiples, voir massives. Par exemple, les centaines d'images qui constituent une vidéo.

Et bien entendu, les langages de programmation nous donnent des outils pour organiser ces données multiples : les structures de données.

Dans ce chapitre, vous allez faire un programme qui calcule votre moyenne. D'abord très simplement, puis de plus en plus efficacement !

Les listes

La liste est sans doute le structure de données la plus intuitive. Elle range des données de meme type, dans un ordre donné. En python, la liste est implémentée dans le type list.

Ca ressemble vraiment beaucoup à une liste que l'on fait dans la vie de tous les jours

Les ambiguités des termes

Parfois, les listes sont appelées "tableaux". Ca dépends des langages et des ouvrages de la littératures.

Dans le programme scolaire de NSI, on demande d'utiliser "tableaux", mais aussi ... de respecter la terminologie de Python (donc "list" ou "liste")...

Ici, j'utiliserai list ou liste, et rarement tableau.

Rappelez-vous juste que en général, quand on parle de "tableau" en programmation, ça corresponds au type list en Python.

On crée une liste vide en utilisant [] :

notes = [] # crée une liste vide (sans élément)
notes_math = [10, 2, 19] # crée une liste contenant 10, 2, et 19, dans cet ordre

On peut ensuite ajouter des éléments à la fin d'une liste en utilisant la méthode append :

notes = [] # crée une liste vide
notes.append(12) # notes vaut [12]
notes.append(17) # notes vaut [12, 17]
notes.append(15) # notes vaut [12, 17, 15]

On peut connaître le nombre d'éléments dans une liste avec len:

print(len(notes)) # 3
print(len([])) # 0
print(len([1, 2, 3, 4, 5])) # 5

Pour accédér au Nième élément d'une liste, on utilise l'opérateur [] :

print(notes[1]) # 17

HEIN QUOI ? 17 ? MAIS VOUS AVEZ PÉTÉ UN CÂBLE MONSIEUR, c'est 12 !

Non j'ai rien pété du tout, c'est juste que en Python, et dans la majorité des langages de programmation, on commence à compter les éléments d'une liste à partir de 0 :

premiere_note = notes[0] # 12
deuxieme_note = notes[1] # 17
troisieme_note = notes[2] # 15

Finalement, on peut parcourir une liste, en utilisant une boucle for:

for note in notes:
    print(note) #affiche successivement 12, 17, 15

Calcul de moyenne : le début

TODO Ici faire un programme qui permet de calculer sa moyenne, avec eventuellement de extensions : moyenne pondérée etc. Mentionner en GROS que le précédent cours est sur les FONCTIONS. histoire de les faire découper.

Pour petit rappel, le chapitre précédent traitait des fonctions. J'insiste :

LE CHAPITRE PRÉCÉDENT TRAITAIT DES FONCTIONS !!!

Voilà, c'est dit, on passe au sujet ?

Activité : calculateur de moyenne

Ecrivez un programme python qui demande des notes à l'utilisateur tant que l'utilisateur n'entre pas une note négative, puis affiche la moyenne des notes positives entrées.

Par exemple :

Entrez une note : 17
Entrez une note : 12
Entrez une note : 14
Entrez une note : 13
Entrez une note : -1
Moyenne de 17, 12, 14, 13 : 14

J'ai vraiment besoin de le redire ? Sérieusement ?

LE CHAPITRE PRÉCÉDENT TRAITAIT DES FONCTIONS !!!

Essayez de découper votre code en fonctions :

  • Demander les notes
  • Calcul de la moyenne
  • Affichage de la moyenne

Demander les notes :

Partez d'une liste vide, puis ajoutez les notes une par une en les demandant !

Eventuellement, commencez par demander un nombre fixe de notes si c'est plus simple :

def demander_notes():
    notes = #ici, création de la liste de notes (vide)
    for _ in range(4): # on demande 4 notes
        rep = #demander d'entrer une note
        #ici, ajout de rep dans notes

    return notes

Calcul de la moyenne :

faites la somme des notes avec une boucle for.

Puis divisez par le nombre de notes.

def moyenne(notes):
    somme = 0
    for ... in ... : #completer
        somme += ... 

    return somme / ... #completer
def demander_notes():    
    note = 0
    notes = []
    while note >= 0:
        note = float(input("Entrez une note : "))
        if note >= 0:
            notes.append(note)

    return notes 


def moyenne(notes):
    somme = 0
    for note in notes : 
        somme += note 

    return somme / len(notes)


def afficher_moyenne(moyenne):
    print("moyenne :", moyenne)


notes = demander_notes()
moy = moyenne(notes)
afficher_moyenne(moy)

Types séquences

Les listes font partie de la famille des séquences, c'est à dire des structures de données qui retiennent des valeurs dans un ordre donné.

Il y a d'autres types séquences en Python, qui sont bien entendu le sujet de la suite de ce chapitre.

Les types séquences se manipulent plus ou moins de la même manière, ce qui va beaucoup alléger le chapitre.

Str, chaines de caractères

Vous avez déjà manipulé des chaines de caractères (type str). Si si, vous savez, entre guillemets :

"Ceci est une chaîne de caractères"

Les chaines de caractères sont composées de caractères, dans un ordre donné.

On crée une chaine de caractères avec "" :

chaine_vide = ""
chaine_non_vide = "du contenu tkt"

Pour le reste, c'est presque comme les listes :

On peut accéder à un caractère de la chaîne avec [], comme pour une liste :

une_chaine = "abcdef"
premier_car = une_chaine[0] #ca commence à 0, comme les listes !
deuxieme_car = une_chaine[1]
troisieme_car = une_chaine[2]

On peut connaître la longueur d'une chaîne en utilisant len :

longueur_chaine = len("abcdef") #vaut 6

On peut parcourir une chaine à l'aide d'une boucle for :

une_chaine = "abcdef"
for car in une_chaine:
    print(car) #affiche successivement a, b, c, d, e, et f.

Il y a quand même des différences :

On ne peut pas append un caractère à une chaine, mais on peut concaténer deux chaines avec + :

chaine_1 = "Bonjour"
chaine_2 = " le monde"
chaine_3 = chaine_1 + chaine_2 #vaut "Bonjour le monde"

A noter que ca marche aussi pour les listes :

liste_1 = [1, 2]
liste_2 = [3, 4, 5]
liste_3 = liste_1 + liste_2 #vaut [1, 2, 3, 4, 5]

Aussi, on peut découper une chaîne de caractères à l'aide de split :

Activité : expérimentation rapide

Exécutez le bout de code suivant dans un fichier à part :

une_chaine = "Félix, Pomme, VTT, Montagne"
res = une_chaine.split(",")
print(res)

Expliquez ce que fait split ?

Quel est le type de la valeur retournée par split ?

split découpe une chaîne de caractères sur un caractère.

La valeur retournée par split est une liste de chaines.

Calcul de moyenne : toutes les notes d'un coup

Activité : toutes les notes d'un coup

Modifiez le programme de calcul de moyenne pour que, au lieu que l'utilisateur entre les notes une par une, il les rentre toutes en une fois, séparées par des virgules.

Par exemple :

Entrez les notes : 10,12,11
Moyenne : 11

Vous devez séparer la chaine, puis convertir chaque élément en nombre.

Si comme je vous avais dit, vous avez

DÉCOUPÉ VOTRE CODE AVEC DES FONCTIONS

Normalement, vous n'avez qu'a modifier la fonction demander_notes :

def demander_notes():    
    notes = input("entrez les notes : ")
    notes_chaines = notes.split(",")
    notes_nombres = []
    for note in notes_chaines:
        notes_nombres.append(float(note))
    return notes_nombres

Magique, non ?

Parcours avec while

Parfois, la boucle for n'est pas suffisante pour parcourir une liste (ou un autre type séquence).

Dans ce cas, on utilise une boucle while, de la forme suivante :

i = 0 #i pour itérateur ou index
while i < len(liste):
    element = liste[i]
    #code
    i+=1

Toute boucle for peut-être transformé en while, mais l'inverse n'est pas vrai !

Activité : de for à While

Transformez la boucle for suivante en un while

chats = ["pedro", "chaussette", "Xx-MouseKiller3000-xX"]

for chat in chats:
    print(chat)
chats = ["pedro", "chaussette", "Xx-MouseKiller3000-xX"]

i = 0
while i < len(chats):
    chat = chats[i]
    print(chat)
    i+=1

On peut aussi être plus concis :

chats = ["pedro", "chaussette", "Xx-MouseKiller3000-xX"]

i = 0
while i < len(chats):
    print(chats[i]) #en mettant directement chat ici
    i+=1

Calcul de moyenne : coefficients

Activité : coefficients

Modifiez le programme de calcul de moyenne pour que l'utilisateur puisse spécifier les coefficients de chaque note.

Par exemple :

Entrez les notes : 10,12,11
Entrez les coefs : 1,2,1
Moyenne : 11.25

Je vous ai déjà dit de

DÉCOUPER VOTRE CODE AVEC DES FONCTIONS

il me semble...

Essayez de faire ça sur du papier... Ca va vous aider.

Si vous ne voyez pas comment faire, appelez votre prof !

On écrit une nouvelle fonction demander_coefficients, qui est presque un copier-coller de demander_notes :

def demander_coefficients():    
    coefs = input("entrez les coefficients : ")
    coefs_chaines = coefs.split(",")
    coefs_nombres = []
    for coef in coefs_chaines:
        coefs_nombres.append(float(coef))
    return coefs_nombres

Ensuite, on modifie moyenne pour qu'elle calcule avec les coefs. Pour ça, on a besoin d'une boucle while, pour parcourir à la fois notes et coefs :

def moyenne(notes, coefs):
    somme = 0
    somme_coefs = 0

    i = 0
    while i < len(notes):
        somme += notes[i] * coefs[i]
        somme_coefs += coefs

    return somme / somme_coefs

Finalement, on adapte le reste du code :

notes = demander_notes()
coefs = demander_coefficients()
moy = moyenne(notes, coefs)
afficher_moyenne(moy)

Quel est le gros défaut de cette solution ?

Que se passe-t-il si on essaie de rentrer beaucoup de notes ?

Le gros défaut de cette solution est que les coefficients ne sont pas directement entrés avec les notes. Ca peut être source de confusion pour l'utilisateur.

On va essayer d'améliorer ça.

Tuple, les... t-uplets

Une paire, association de deux éléments, est un 2-uplet : (1, 2)

Un triplet, association de trois éléments, est un 3-uplet : (1, 2, 4)

Un quadruplet, association de quatre éléments, est un 4-uplet : (1, 2, 4, 0)

Si on généralise le concept à un nombre arbitraire t d'éléments, on obtient un t-uplet. En Python, ça corresponds au type tuple.

Pour créer un tuple, on utilise des parenthèses ().

tuple_vide = ()
tuple_non_vide = (1, 2, 'a')

Pour le reste, c'est presque comme les listes :

On peut accéder à un élémént d'un tuple avec [], comme pour une liste :

personne = ("Felix", "Bertoni", 29)
prenom = un_tuple[0]
nom = un_tuple[1]
age = un_tuple[2]

On peut connaître la longueur d'un tuple en utilisant len :

longueur_tuple = len(personne) #vaut 3

On peut parcourir un tuple à l'aide d'une boucle for :

for e in personne:
    print(e) #affiche successivement Felix, Bertoni, et 29

Il y a quand même des différences :

Comme pour les chaînes, on ne peut pas append un élément à un tuple, mais on peut concaténer deux tuples avec + :

tuple_1 = (1, 2, 3)
tuple_2 = ("a", "b", "c")
tuple_3 = tuple_1 + tuple_2 #vaut (1, 2, 3, "a", "b", "c")

Ici, vous avez probablement l'impression que les tuples sont juste des listes en moins bien.

En réalité, ils ont d'autres différences que l'on verra dans les chapitres suivants.

Mais la plus important est leur usage sémantique.

Sémantique ?

La sémantique, c'est la manière dont le sens de notre code est défini.

Activité : tuple vs liste

Pour stocker les données représentant un élève, on utilise généralement un tuple :

eleve = ("Félix", "Bertoni", 29)

Pour stocker une paire de coordonnées en 2D, on utilise généralement un tuple :

point = (21.3, 19.0)

Pour stocker des notes, on utilise généralement une liste :

notes = [12, 20, 11, 17]

Essayez de comprendre les raisons qui dictent le choix d'un tuple ou d'une liste.

Quand vous pensez avoir trouvé, appelez votre prof pour en discuter.

Essayez de représenter d'autres personnes...

D'autres ensemble de notes...

Et observez la forme qu'a les données.

Un tuple est généralement utilisé pour manipuler un ensemble de données :

  • de taille fixe (et généralement réduite)
  • où les différents éléments ont des significations différentes, données par leur position
#exemple de structure (significations)
eleve = (prenom, nom, age)
point = (x, y)

dans un tuple, on s'autorise à avoir des élements de types différents :

#exemple de structures (types)
eleve = (str, str, int)
point = (int, int)

Une liste est généralement utilisée pour manipuler un ensemble de données :

  • de taille variable
  • où tous les éléments ont la même signification
#exemple de structure (significations)
notes = [note1, note2, note3, ...]

dans une liste, on s'impose d'avoir un seul et même type pour tous les éléments :

#exemple de structure (types)
notes = [float, float, float, ...]

Activité : structuration

Cette activité à pour but de vous faire réfléchir sur l'utilisation de tuples et de listes.

A chaque question est présentée une bonne réponse. Si vous avez une réponse différente, elle n'est pas forcément fausse, demandez un avis à votre prof.

Comment représenter les données d'une classe, avec le nom, le prénom, et la moyenne de chaque élève ?

Chaque élève a un nom, un prénom et une moyenne. C'est un ensemble de taille fixe, où chaque élément à une signification différente. On utilise donc un tuple.

Une classe est un ensemble d'élèves, dont le nombre peut varier. On utilise donc une liste.

Une classe est alors représentée ainsi :

classe = [ (prenom1, nom1, moyenne1), (prenom2, nom2, moyenne2), (prenom3, nom3, moyenne3), ...]

Calcul de moyenne : notes et coefs, tout d'un coup

Activité : notes et coefs, tout d'un coup

Modifiez le programme de calcul de moyenne pour que l'utilisateur puisse rentrer les notes et les coefficients en une seule fois, tout en gardant chaque coefficient proche de la note correspondante.

Par exemple :

Entrez les notes : 10/1,12/2,11/1
Moyenne : 11.25

Cette activité est relativement difficile. Prenez votre temps et n'hésitez pas à demander de l'aide en cas de blocage.

Commencez par trouver comment structurer les notes et les coefficients.

Il vous faut d'abord séparer chaque paire de note et coef

"10/1,12/2,11/1" -> ["10/1","12/2","11/1"]

puis séparer chaque note et son coef

["10/1"  ,"12/2",  "11/1"]
    |        |        |
[(10, 1), (12, 2), (11, 1)]

Et n'oubliez-pas :

Ainsi font font font,

Ainsi font font font,

Les petites

FON... FONCTIONS !

On va représenter les notes comme suit :

notes = [ (note1, coef1), (note2, coef2), ...]

On commence par modifier la fonction demander_notes. C'est le gros du travail. Pour plus de clareté on se crée une fonctions separer_note_coef :

def separer_note_coef(chaine):
    note_coef = chaine.split("/")
    return (float(note_coef[0]), float(note_coef[1]))

def demander_notes():    
    notes_chaine = input("Entrez les notes : ")
    notes_chaines_sep = notes_chaine.split(",") #on sépare les paires
    notes = []
    for chaine in notes_chaines_sep:
        notes.append(separer_note_coef(chaine)) #on sépare chaque paire

    return notes

On peut alors supprimer demander_coefficients, la fonction n'est plus utile.

Ensuite, on adapte la fonction moyenne à cette nouvelle structure :

def moyenne(notes):
    somme = 0
    somme_coefs = 0
    for note in notes :  #note est un tuple (note, coef)
        somme += note[0] * note[1] #note[0] la note, note[1] le coef
        somme_coefs += note[1]

    return somme / somme_coefs

Pour terminer, on modifie le reste du code :

notes = demander_notes()
moy = moyenne(notes)
afficher_moyenne(notes, moy)

Sucre syntaxique

TODO : fonction map, zip, unpacking...