T- 6 - Complexité de méthodes du type list utilisé en python


Le type list python ne correspond pas au types de donnée abstrait liste étudié dans ce cours.

Néanmoins il est intéressant de connaitre les complexité des méthodes telles qu'elles existent dans python.

Commencons par la méthode len(), qui dans le type abstrait est considérée comme O(n)

Exemple : compexité de len()
plus

Exemple : complexité de insert - insérer en tête
Premier cas: insertion en début de liste

Exemple : complexité de insert - insérer en queue
Premier cas: insertion en début de liste

Publié dans Non classé

T-1.2 - Revisions : modéliser une situation

Les listes

Définition : conteneur regroupant des éléments, ordonnés, repérés par un indice.

exemples : lst = [ 1, 2, 3 ] lst=["a" , "b" , "c" ] lst = [1, [2,3], "abc" ] etc..

Accès ou modifier des éléments :

lst = [1, 2, 3, 4, 5, 6]
lst[0] vaut 1  lst[3] vaut 4
lst[2:4] vaut [2, 3, 4]
lst[:3] vaut [1, 2, 3] 
lst[3:] vaut [4, 5, 6]
pour modifier : lst[2] = 10 -> lst vaut [1, 2, 10, 4, 5, 6]

Parcourir

Parcours sur les éléments :
lst = [1, 2, 3, 4]
for elem in lst :
    print(elem)
affichera :
1
2
3
4

Parcours sur les indices :
lst = [1, 2, 3, 4]
for i in range(len(lst)) :
    print(lst[i])
affichera le même résultat

méthodes

Ajouter un élément :

Avec append :
lst = [1, 2, 3, 4]
lst.append(5) -> lst vaut [1, 2, 3, 4, 5]

Avec insert : 
lst = [1, 2, 3, 4]
lst.insert(0, "A") -> lst vaut ["A", 1, 2, 3, 4]
Retirer un élément :

Avec pop:
lst = [1, 2, 3, 4]
lst.pop() -> renvoie 4 et lst vaut [1, 2, 3]
lst.pop(0) -> renvoie 0 et lst vaut [2, 3, 4]
lst.pop(1) -> renvoie 2 et lst vaut [1, 3, 4]

Avec remove: 
lst = [1, 2, 3, 4]
lst.remove(1) -> lst vaut [2, 3, 4] (erreur si élément non présent)

avec del :
lst = [1, 2, 3, 4]
del lst[1] -> lst vaut  [1, 3, 4] (retire l'élément d'indice 1)
trier :

Avec sort():
lst = [6, 2, 7, 4]
lst.sort() -> ne renvoie rien et modifie lst qui vaut [2, 4, 6, 7]


Avec sorted: 
lst = [6, 2, 7, 4]
sorted(lst) renvoie une nouvelle liste contenant : [2, 4, 6, 7]
en général utilisé ainsi :
lst2 = sorted(lst1)
divers

count():
lst = [6, 2, 7, 4, 2, 1, 2]
lst.count(2) -> renvoie 3 (2 est trois fois dans la liste)

index() :
lst.index(2) renvoie 1 (la première occurrence de  2 est à l'indice 1)
index renvoie une erreur si l'élément n'est pas présent

Initialiser et remplir une liste

Exemple : créer une liste contenant les entiers de 1 à 10 :

Avec liste vide et append :
lst = []
for i in range(1, 11) :
    lst.append(i)

Avec une initialisation à la bonne longueur (ici, 10 éléments) :
lst = [0]*10 (créé une liste contenant 10 fois l'entier 0)
for i in range(1, 11) :
    lst[i] = i

Exercices

Les algo simples

Tirage du Loto

Exercice de code : Loto
Vous devez générer une liste contenant les entier de 1 à 49. Ensuite, votre code doit tirer, sans remise, 6 numéros qu'on stocke dans une liste, puis, toujours sans remise, un dernier numéro (le numéro complémentaire).
 

CONTRAINTE : Vous ne devez pas utiliser random.choice() même si vous connaissez cette fonction du module random.
 
APPROFONDIR : Envisagez différente façon de coder ce problème, utilisant pop() del ou remove()....
 
Votre code affichera la liste des 6 numéros puis le complémentaire comme ceci :
[31, 3, 12, 45, 13, 27]
18

Doublons

Exercice de code : DOUBLONS
Soit la liste de nombres liste = [5, 1, 1, 2, 5, 6, 3, 4, 4, 4, 2]. A partir de liste, créez une nouvelle liste sans les doublons, et affichez-la.

Nombre mystère

Exercice de code : Nombre mystère
Trouvez le nombre mystère qui répond aux conditions suivantes :

  • Il est composé de 3 chiffres.
  • Il est strictement inférieur à 300.
  • Il est pair.
  • Deux de ses chiffres sont identiques.
  • La somme de ses chiffres est égale à 7.

On vous propose d'employer une méthode dite « brute force », c'est-à-dire d'utiliser une boucle et à chaque itération de tester les différentes conditions.

Les indispensables (donc vous ne pouvez PAS vous en dispenser)

Recherche min/max (curseur)

Voila un algorithme qui intervient dans de nombreux autres. Vous en connaissez au moins un cas....
Dans ce type d'algorithme on parcourt une liste en conservant l'index correspondant à un critère.

On pourrait sans peine changer un peu le problème en : trouver la dernière valeur paire, trouver le dernier mot commençant par Z etc...

Exercice de code : Maximum
Créez une fonction idxMax() qui prend comme argument une liste d'éléments ordonnables et renvoie l'indice du plus grand.
 
CONTRAINTE : vous ne devez pas utiliser la fonction max de python, le but est de la reprogrammer !
 
Quelle est la complexité de cet algorithme ?

Dans l'exercice ci-dessus, on veut l'indice du max.

Il est crucial de ne pas mélanger INDICE et VALEUR, c'est souvent la cause d'erreurs dans les exercices. On lit souvent des choses comme :

def get_idx_min(lst) :
    """ lst liste non vide"""
    min = 0                     # min est le premier INDICE
    for elem in lst :           # parcours sur les VALEURS
        if elem < min:          # on compare 1 VALEURS et un INDICE ! c'est incorrect
                   min = elem   # maintenant min devient une valeur
    return min

Compter sur un critère (compteur)

La notion de compteur est fondamentale. Dans \"Compter le nombre de <un truc> \" le mot qui importe est compter.

Exercice de code : Un compteur sachant compter doit savoir compter sans compter
Créez une fonction compter(lst) qui renoie le nombre de multiples de 3 dans la liste lst.

moyenne des éléments pairs (compteur + accumulateur)

Les accumulateurs et les compteurs sont des pièces maitresse que vous ne pouvez pas ignorer. Voici deux cas basiques d\'utilisation de ceux ci, le compteur pour la moyene (diviser par le nombre de valeurs) et l'accumulateur pour faire la somme.
Exercice de code : moyenne et somme
Créez une fonction somme(lst) et une autre moyPairs(lst) qui prennent comme argument une liste de nombre et renvoient l'une la somme de tous les éléments, l'autre la moyenne des éléments pairs de la liste.

Manipulation et parcours de chaînes

Rappels

chaine = "abcdefabcdef"

Portion de chaine :
chaine[0] vaut "a"
chaine[2:4] vaut "cd"
chaine[:3] vaut "abc"
chaine[2:] vaut "cdefabcdef"
chaine[-1] vaut "f"

Fonctions et méthodes :
longueur : len(chaine) vaut 12
a.find('c') renvoie 2   et a.find('z') renvoie -1
a.replace('a','A') renvoie 'AbcdefAbcdef' et a.replace('a','A',1) renvoie 'Abcdefabcdef'
a.upper() renvoie 'ABCDEFABCDEF'   et 'ABCDEF'.lower vaut 'abcdef'
"a et b".split(" ") renvoie ["a","et","b"]
"a et b, sont 2 nombres".split(",") renvoie ["a et b","sont 2 nombres"]

Parcourir :
for lettre in chaine :
    print(lettre)

Exercice

Exercice de code : Retourner une chaine
Ecrire une fonction reverse_str correspondant aux spécifications ci-dessus.

Les dictionnaires

Définition : conteneur regroupant des éléments, non ordonnés, repérés par une clé (t-uplet nommé).

Les clé jouent le même rôle que les indices des listes

exemples :
dico = { 1: 1, 2:2, 3:3 } # les clé sont des int, la valeurs aussi
dico ={"cle1":2 , "cle2" : 3, "cle3":4 } # les clés sont des str, les valeurs sont int
eleve = { "nom": "Dupond" , "prenom" : "Jean" , "age":15 } # les clés sont str, les valeurs sont de type str ou int

Accès ou modifier des éléments :

eleve = {"nom": "Dupond" , "prenom" : "Jean" , "age":15}
accéder : 
eleve["nom"] vaut "Dupond"
eleve["age"] vaut 15
eleve[0] n'existe pas, il n'y a pas de clé 0 -> KeyError

modifier : 
eleve["nom"] = "Durand" modifie la valeur de la clé nom

méthodes

Ajouter un élément :

Contrairement aux listes, on n'utilise pas une méthode.
On définit simplement une nouvelle clé :
eleve = { "nom": "Dupond" , "prenom" : "Jean" , "age":15 }
Pour ajouter la clé classe :
eleve["classe"] = "TG8"

Retirer un élément :

on utilise del :
eleve = { "nom": "Dupond" , "prenom" : "Jean" , "age":15 }
del eleve["age"] -> eleve vaut {"nom": "Dupond" , "prenom" : "Jean"}
trier : on ne trie pas un dict

divers

keys():
eleve = { "nom": "Dupond" , "prenom" : "Jean" , "age":15 }
eleve.keys() renvoie ["nom" , "prenom" , "age"]
ça ressemble à une liste, ce n'en est pas tout à fait une mais on peut l'utiliser comme une liste.

values() :
eleve = { "nom": "Dupond" , "prenom" : "Jean" , "age":15 }
eleve.values() renvoie ["Dupond" , "Jean" , 15]

items() :
eleve = { "nom": "Dupond" , "prenom" : "Jean" , "age":15 }
eleve.items() renvoie [("nom","Dupond") , ("prenom","Jean") , ("age",15) ]
c'est une liste de tuples.

Initialiser et remplir un dict

Exemple : créer notre élève :

eleve = {}
eleve["nom"] = "Dupond"
eleve["prenom"] = "Jean"
eleve["age"] = 15

Parcourir

Parcours sur les clés (de loin le plus fréquent):
eleve = {"nom": "Dupond", "prenom" : "Jean", "age":15 }
for cle in eleve.keys() :
     print("la cle est : ", cle," sa valeur est:", eleve[cle])
affichera :
la cle est : nom sa valeur est: Dupond
la cle est : prenom sa valeur est: Jean
la cle est : age sa valeur est: 15

comme le parcours sur les clés est fréquent on peut écrire :
for cle in eleve :
    print("la cle est : ", cle, " sa valeur est:", eleve[cle])
qui fera la même chose.

Parcours sur les valeurs (assez rare et peut poser problème, on ne sait pas retrouver les clés):
for val in eleve.values() :
    print(" la valeur est:", val)

peut être utilisé quelques fois. Exemple :
ventes = {"geoffroy":12 , "arnaud" : 13 , "gilles":16 , "jean" : 5}
def moyenne_ventes(ventes) : 
   total = 0
   for val in ventes.values() : 
       total += val
   return total / len(ventes)

Mais souvent on préfèrera itérer quand même sur les clés :
def moyenne_ventes(ventes) :
    total = 0
    for cle in ventes.keys() :
        total += vente[cle]
    return total / len(ventes)


Parcours sur les items:
for item in eleve.items() :
    print(item)
affichera :
('nom', 'Dupond')
('prenom', 'Jean')
('age', 15)

Exercices un peu plus élaborés utilisant listes, chaines et dictionnaires

Le paradoxe du Duc de Toscane

Exercice de code : Le paradoxe du Duc

Votre code affichera le résultat avec les pourcentages arrondis à 0.01 près sous cette forme :
fréquence de 9 : 11.5
fréquence de 10 : 12.81

Triangle de Pascal

Exercice de code : Le triangle de Pascal
Voici le début du triangle de Pascal :

  1. 1
  2. 1 1
  3. 1 2 1
  4. 1 3 3 1
  5. 1 4 6 4 1.
  6. 1 5 10 10 5 1
  7. [...]

Vous représenterez chaque ligne par une liste.
Ainsi la ligne 1 est représentée par [1], la ligne 2 par [1, 1], etc...
Déduisez comment une ligne est construite à partir de la précédente.
Par exemple, à partir de la ligne 2 : [1, 1], construisez la ligne suivante (ligne 3 : [1, 2, 1]) et ainsi de suite.
Implémentez cette construction en Python en créant une fonction.
Ecrire le programme pour qu'il affiche les 20 premières lignes du triangle de Pascal

Des listes, des chaines, des dictionnaires
(application en bio-informatique)

Séquence d'ADN

Exercice de code : Un brin d'ADN
Créez une fonction seq_alea() qui prend comme argument un entier positif taille représentant le nombre de bases de la séquence et qui renvoie une séquence d'ADN aléatoire sous forme d'une liste de bases. (c'est à dire une liste contenant uniquement les éléments "A" "T" "C" ou "G").
 
Utilisez la méthode .append() pour ajouter les différentes bases à la liste et la fonction random.choice() du module random pour choisir une base parmi les 4 possibles.
 
Aide!

Séquence d'ADN complémentaire inverse

Rappel : les dictionnaires sont des structures de données qui utilisent des clés au lieu des indices.

dico={"NOM":"LOVELACE" , "Prénom" : "Ada"} est un dictionnaire.

  • "NOM" et "Prénom" sont les clés
  • "LOVELACE" et "Ada" sont les valeurs associées à ces clés.
  • ("NOM" : "LOVELACE") est un elément du dictionnaire.

Par exemple :

Exemple : Objets géométriques

 

Application :

dans l'exercice ci-dessous, la structure de donnée dictionnaire est bien adaptée. A vous de jouer !

Exercice de code : Brin d'ADN complémentaire
Créez une fonction comp_inv() qui prend comme argument une séquence d'ADN sous la forme d'une chaîne de caractères, qui renvoie la séquence complémentaire inverse sous la forme d'une autre chaîne de caractères
 
Par exemple, la chaine complémentaire inverse de AACGCT est TTGCGA :

  • les A sont changés en T et inversement
  • les C en G et inversement.


 
CONTRAINTE : vous devez utiliser un dictionnaire dont les clefs sont les bases ATCG et les valeurs, les bases de remplacement de chaque clef.
Votre code ne doit contenir aucun test.
 
 
Aide 1! Aide 2!

Séquence d'ADN aléatoire 2 (Approfondissement)

Dans cet exercice vous allez avoir besoin de random.shuffle(). Voici un exemple de l'utilisation de cette méthode :

Exemple : à en perdre son latin...

En utilisant étudiant l'exemple ci-dessus, pour bien comprendre le fonctionnement de la méthode .shuffle, vous pouvez aborder l'exercice ci-dessous :

Exercice de code : ADN aléatoire contraint
Créez une fonction seq_alea_2() qui prend comme argument 4 entiers représentant respectivement la longueur de la séquence et les pourcentages de chacune des 3 bases A, T et G (le pourcentage de C etant alors déterminé). La fonction générera aléatoirement une séquence d'ADN qui prend en compte les contraintes fournies en arguments et renverra la séquence sous forme d'une liste. Utilisez cette fonction pour générer aléatoirement une séquence d'ADN de 50 bases contenant 10 % de A, 30 % de T, 50 % de G et 10 % de C. Conseil : la fonction random.shuffle() du module random vous sera utile.

Les listes de listes : lignes, colonnes et diagonales

Exemple

Ce sont des listes, dont les éléments sont des listes. Les sous listes peuvent contenir des éléments de types quelconques (numériques, string etc...)

lst = [[11,12,13], [21, 22, 23], [31 , 32, 33]]

lst[1] vaut [21, 22, 23]
et donc :
lst[1][0] vaut 21 (l'élément d'indice 0 dans lst[1])

lignes, colonnes et diagonales

parcourir la liste de liste et afficher les lignes :

lst = [[11,12,13], [21, 22, 23], [31 , 32, 33]]

# parcours sur les indices :
for num_ligne in range(len(lst)) :
    print(lst[num_ligne])

# on aurait put faire un parcours sur les éléments:
for ligne in lst :
    print(ligne)
afficher les colonnes:

lst = [ [11,12,13] , [21, 22, 23] , [31 , 32, 33] ]

les colonnes ne correspondent pas à un élément de la liste
mais peuvent être reconstituées en piochant dans les éléments des
sous listes :
colonne1 = [lst[0][1], lst[1][1], lst[2][1]]

ce n'est pas très joli ! on préfère :
colonne[num_col] = [lst[i][col] for col in range(3)]

afficher la diagonale 1 (en haut à gauche à en bas à droite):

| X  .  . |
| .  X  . |
| .  .  X |
lst = [[11, 12, 13], [21, 22, 23], [31 , 32, 33]]

diag1 = [lst[i][i]  for i in range(3)]


afficher la diagonale 2 (en haut à droite à en bas à gauche):

| .  .  X |
| .  X  . |
| X  .  . |
lst = [[11,12,13], [21, 22, 23], [31 , 32, 33]]

diag2 = [lst[i][2 - i]  for i in range(3)]

plus généralement, pour un tableau carré de taille n :
col = [lst[i][col] for i in range(n)]
diag1 = [lst[i][i] for i in range(n)]
diag2 = [lst[i][n - i] for i in range(n)]

Les listes de dict

A venir ultérieurement

1ere - Traitements des chaines de caractères

Le maniement des chaînes de caractères est important dans de nombreuses situations :

  • Extraire une information d'un texte.
  • Formater une chaîne pour un affichage lisible.
  • des algorithmes divers, comme par exemple celui permettant de proposer un mot lorsque l'utilisateur tape les premières lettres, ou des correcteurs ortographiques etc..
Accéder à un caractère dans la chaîne

Les chaînes sont en réalité des listes de caractères, et peuvent être traitée comme des listes : Les caractères sont repérés par leur indice :

Indice0123456789101112
caractèreHello,World!
correspondance caractère <-> indice

Notez que le caractère à l'index 6 est un espace.

Exemple : Extraire un caractère d'une chaîne

Longueur d'une chaîne
Exemple : Longueur d'une chaîne
sous chaîne
Exemple : Sous chaîne
Afficher une sous chaine
Coller des chaînes: +

Nous savons tous que 1+2=3.

Avec les chaînes, nous obtenons le résultat suivant à la place:"

Exemple : Sous chaîne
Concatenation

Attention : On ne peut additionner que des éléments de même type

Exemple : TypeError
Exécutez ce code et prendre note de l'erreur de type, que vous rencontrerez souvent et que vous devez comprendre.
TypeError: unsupported operand type(s) for +: 'int' and 'str'
Donne plusieurs informations :

  • TypeError indique qu'on a effectué une opération entre deux types imcompatibles
  • for + indique l'opération en cause, ici c'est l'opérateur +
  • int and str : les 2 opérandes sont : le premier un entier, le second une chaîne
Conversions de chaînes: +

Conversion de chaine de caractères

Comme vous le savez déjà, nous pouvons convertir une chaine de caractères en entier et inversement.

Pour cela, nous utilisons les fonctions str() et int().

Exemple : int et str
Exécutez ce code.

Mais nous pouvons aussi convertir une chaîne en liste :

Exemple : str en liste
Exécutez ce code.

quelques compléments pour utiliser print

On a parfois besoin d'afficher successivement plusieur texte, sans passer à la ligne. Cela est possible en utilisant, dans la fonction **print**, l'option end=""

Exemple : exemple sans end=..
Exécutez et observez

Ajoutons l'option end = ""

Exemple : avec end=""
Exécutez et observez

ou end = " "

Exemple : avec end=" "
Exécutez et observez

Exercices

Niveau 1


Fonction repeteMot

Exercice de code : Le perroquet
Ecrire une fonction qui répète un même mot un certain nombre de fois au choix.

Il y aura donc 2 arguments : une valeur numérique et un mot.
Ex: Repete(3,"Ok") affichera "OkOkOk"
La fonction ne renvoie rien, elle affiche simplement.

CONTRAINTE :Vous ne devez pas utuliser de concaténation, seulement avec l'option end=..

Parcours de chaîne

Exemple : parcours de chaîne SUR LES INDICES
Parcours de chaine (sur les indices)
Exemple : parcours de chaîne
Parcours sur les caractères

Pour éviter de vous tromper :

Nommez l'itérateur soigneusement l'iterateur :

  • i pour un parcours avec les indices : for i in range( len(lst) ) :
  • caractère (ou lettre) pour un parcours sur les caracteres : for caractere in txt :

Ces deux façons de procéder se retrouvent pour tout les itérables. Un itérable est un type de variable contenant des éléments. Par exemple, les chaînes de caractères, et les listes, sont des itérables : on peut itérer sur les lettres d'un mots, sur les éléments d'une liste etc....

Nous retrouveront donc les mêmes parcours pour les listes, et pour bien d'autres structures plus tard.

exercice avec parcours de chaines

Exercice de code : Première occurence
En étudiant l'exemple précédent, vous pouvez écrire une fonction search(lettre : str,txt:str) qui parcours la chaîne txt et qui renvoie un entier correspondant à l'indice de la première occurrence du caractère lettre dans txt.

Si la lettre n'est pas trouvée, la fonction doit renvoyer -1.
Aide 1 Aide 2
Modifiez pour que la fonction renvoie la dernière occurrence (au lieu de la 1ere)
Exercice de code : Dernière occurence
En modifiant le code de l'exercice précédent, vous pouvez écrire une fonction search(lettre,txt) qui parcours la chaîne txt et qui renvoie un entier correspondant à l'indice de la dernière occurrence du caractère lettre dans txt. Si la lettre n'est pas trouvée, la fonction doit renvoyer -1.
Aide 1

Niveau 2

Fonction renverseSTR
Exercice de code : Retournement
Ecrire une fonction renverseSTR(txt) -> str qui prend une chaine txt en paramètre, et qui renvoie la chaine txt écrite en partant de la fin :
Ex: renverseSTR("NSI") va renvoyer "ISN"
renverseSTR("loi") va renvoyer "iol"

Palindrome

Exercice de code : Palindrome
Un palindrome est un mot qui s'écrit de la même façon à l'endroit et à l'envers. Par exemple le mot

ressasser

est un palindrome: la première et la dernière lettres sont les mêmes (r), la deuxième et l'avant dernière également (e), etc.

Ecrivez une fonction estPalindrome(S) qui prend une chaîne txt comme entrée et renvoie True si la chaîne est un palindrome etFalse autrement.

Le correcteur va générer une fonction reverseSTR similaire à celle de l'exercice précédent. Il est recommandé de l'utiliser dans cet exercice.

Niveau 3

in

Nous allons maintenant chercher non plus un caractère unique, mais une sous chaîne dans la chaine. Tout d'abord, voyons la fonction pythn qui sait déjà faire cela :

Exemple : sous-chaine in chaine
Savoir si une chaine s est une sous chaine d'une autre chaine txt

Mais nous voulons coder une fonction qui fasse cela. Vous aurez besoin d'étudier cet exemple :

Exemple : sous chaine glissée
Un autre parcours d'une chaine, ou l'on extrait une partie de la chaîne

Si vous avez bien compris les 2 exemples ci-dessus, vous pouvez maintenant réussir cet exercice :

Exercice de code : coder in
Sans utiliser in tel que montré dans l'exemple précédent, écrire une fonction estDans(s : str,txt:str) -> bool qui renvoie True si la chaine s apparait dans la chaine txt, et False sinon. On se limitera au cas ou chechée, s, est une chaine de 2 caractères seulement.

replace et concaténation

La méthode des chaînes replace() en python permet de remplacer une sous chaine par une autre. Etudiez cet exemple :

Exemple : sous chaine glissée
Remplacement dans une chaine

Par ailleurs, rappelons le principe de la concaténation et au passage de la réplication :

Exemple : concaténation et réplication
Concaténer et réplique une chaine

Exercice de code : remplacer
Sans utiliser replace tel que montré dans l'exemple ci-dessus, écrire une fonction remplacers(s1 : str,s2 : str, txt : str) -> str qui renvoie la chaine txt après remplacement de la première occurence de la chaine s1 par la chaine s2. Si la chaine s1 n'est pas trouvée, la fonction renvoie la chaine de départ.
Attention cet exercice est difficile. Inspirez vous de l'exercice précédent (in) et regardez les sorties attendues, comparez avec ce que vous obtenez. Avec patience vous finirez par y arriver !

P5.1 La boite à outils

  • Le tryptique CAC

  • La complexité

  • Construction de listes par ajout successifs

  • TP moyenne glissée

Premiers algorithmes

Utiliser un compteur, un accumulateur, ou un curseur

Dans de nombreux cas, on doit :

  • compter le nombre d'occurence d'une condition, dans ce cas, on utilisera un compteur
  • sommer (ou faire un produit) dans une boucle, dans ce cas, on utilisera un accumulateur
  • mémoriser la position d'un élément particulier, dans ce cas, on utilisera un curseur

Un compteur en action

Les compteur sont des variables qu'on incrémente quand on trouve un éléments correspondant à un critère. Parfois il n'y a pas vraiment de critère, on compte simplement tout les éléments ou toutes les occurrences, mais la notion de comptage est fréquente en algorithmique. Nous avons déjà vu des utilisations de compteurs.

Multiples de 3

Ecrire une fonction qui prend en argument une liste de nombres et renvoi le nombre de multiples de 3 dans cette liste

Exercice de code : Compte les multiples de 3
Ecrire la fonction compterMult3(lst). Une liste lst sera générée pour tester votre code.

L'algorithme en pseudo-code

Le pseudo-code est indépendant du langage, c'est une description des opérations a faire pour accomplir une tâche. Il est important de bien distinguer algorithme et code. Lorsque vous écrivez un pseudo-code vous vous libérez des questions de syntaxe pour vous concentrer uniquement sur l'algorithme.

pseudo code de l'algorithme de recherche des multiples de 3 dans une liste :

fonction compterMult3(lst) :
     n ← 0
     pour element dans lst :
          si element%3 =  0 :
                 n ← n+1
          fin de si
     fin de pour
     renvoyer n

Notion de complexité

L'algorithme contient une boucle sur les éléments de la liste lst.

  • Avant la boucle on a 1 affection
  • La boucle est exécutée N fois (N=longueur de la liste)
  • Dans la boucle il y a 1 opération (%), un test, une addition et une affectation. Au total 4 opération élémentaires
  • Après la boucle il n'y a rien

On a donc au total, 4N + 1 opérations élémentaires dans ce code. 4N+1 est une fonction linéaire, on dit qu'on a une complexité linéaire et on note C=O(N)

Exemple
Vérifions la complexité de compterMult3()

Vous observez que lorsque le nombre N d'éléments de la liste est multiplié par 10, le temps de calcul est multiplié aussi par un facteur du même ordre de grandeur. Nous observons bien ici une complexité linéaire.

Un accumulateur en action

Pour sommer ou multiplier (ou soustraire ou diviser) dans une boucle, on utilise une variable accumulateur. Nous avons déjà vu des utilisations d'accumulateurs.

Calcul de la moyenne
Exercice de code : Calcul de moyenne
Ecrire la fonction somme(lst). Une liste lst sera générée pour exécuter votre code.

Ici il n'est pas question de compter, mais de faire la somme. Nous avons déjà vu cet algorithme plusieurs fois.

pseudo code de l'algorithme de la moyenne :

fonction moyenne(lst) :
     somme ← 0
     pour element dans lst :
          somme ← somme + element
     fin de pour
     renvoyer somme/len(lst)

Notion de complexité

L'algorithme contient une boucle sur les éléments de la liste lst.

  • Avant la boucle on a 1 affection
  • La boucle est exécutée N fois (N=longueur de la liste)
  • Dans la boucle il y a une addition et une affectation. Au total 2 opération élémentaires
  • Après la boucle il n'y a rien

On a donc au total, 2N + 1 opérations élémentaires dans ce code. 2N+1 est une fonction linéaire, on dit ici aussi qu'on a une complexité linéaire et on note C=O(N)

Exemple
Vérifions la complexité de moyenne()

Vous observez là encore que lorsque le nombre N d'éléments de la liste est multiplié 10, le temps de calcul est multiplié aussi par un facteur du même ordre de grandeur. Nous observons donc encore bien ici une complexité linéaire.

Un curseur en action

Les curseurs sont des variables qui retiennent la position (l'index) d'un élément présentant une caractéristique particulière dans une liste. Un bon exemple est la recherche de la position du max des éléments d'une liste.

Indice du maximum
Exercice de code : Indice du maximum
Ecrire la fonction idxMax(lst). Une liste lst sera générée pour exécuter votre code.

Ici il n'est pas question de compter ou de sommer, mais de mémoriser la dernière position du max parmi les éléments déjà parcourus.

pseudo code de l'algorithme de recherche de l'indice du max des éléments d'une liste :

fonction idxMax(lst) :
     idxMax ← 0
     pour i allant de 1 à len(lst)-1 :
         si lst[i] > lst[idxMax] :
               idxMax ← i
         fin de si
     fin de pour
     renvoyer n
La boucle va de 1 à len(lst) -1 si les indices vont de 0 à len(lst)-1 comme en python. on écrit i in range( 1,len(lst) )

remarque : Dans d'autres langages les indices vont de 1 à len(lst), dans ce cas la boucle ira de 2 à len(lst).

Notion de complexité

L'algorithme contient une boucle sur les éléments de la liste lst (en partant du 2ème)

  • Avant la boucle on a 1 affection
  • La boucle est exécutée N-1 fois (N=longueur de la liste)
  • Dans la boucle il y a une comparaison et une affectation. Au total 2 opération élémentaires
  • Après la boucle il n'y a rien

On a donc au total, 2N + 1 opérations élémentaires dans ce code. On a de nouveau une complexité linéaire et on note C=O(N)

Exemple
Vérifions la complexité de idxMax()

Vous observez là encore que lorsque le nombre N d'éléments de la liste est multiplié 10, le temps de calcul est multiplié aussi par un facteur du même ordre de grandeur. Nous observons donc encore bien ici une complexité linéaire.

Variante

Il existe une variante (qu'on retrouve généralement dans tous les algorithme utilisant un curseur) à l'algorithme que nous venons de voir.

Si, au lieu de l'indice de la valeur maxi, on cherche la valeur elle même, l'algorithme est légèrement différent.
Ecrivez le pseudo-code modifié pour satisfaire cette recherche, puis codez le ici :

Exercice de code
Ecrire la fonction valMax(lst) qui renvoie la valeur max d'une liste
ATTENTION : vous ne pouvez pas utiliser range dans cet exercice !
pseudo code de l'algorithme de recherche du max des éléments d'une liste :

fonction valMax(lst) :
     valMax ← lst[0]
     pour i dans lst[1:] :
         si i > valMax :
               valMax ← i
         fin de si
     fin de pour
     renvoyer n

Exercices

sommes et moyenne des valeurs paires

Ecrire l'algorithme d'une fonction sommePaires(lst) qui renvoie la somme des valeurs paires d'une liste.

Exercice à choix multiple
Dans sommesPaires vous aurez besoin d'un compteur ?
Correct !
Exercice à choix multiple
Dans sommesPaires vous aurez besoin d'un curseur?
Correct !
Exercice à choix multiple
Dans sommesPaires vous aurez besoin d'un accumulateur ?
Correct !

Ecrire un second algorithme pour moyPaires qui renvoie la moyenne des valeurs paires d'une liste.

Exercice à choix multiple
Dans moyPaires vous aurez besoin d'un compteur ?
Correct !
Exercice à choix multiple
Dans moyPaires vous aurez besoin d'un curseur?
Correct !
Exercice à choix multiple
Dans moyPaires vous aurez besoin d'un accumulateur ?
Correct !

moyenne pondérée

N'oubliez pas que vous pouvez visualiser l'exécution de votre code pour vous aider à le mettre au point.

Exercice de code : moyenne coefficientée
Ecrire une fonction moyPondee(notes , coefs) qui renvoie la moyenne coefficientée.
Exercice à réponse courte
Combien y'a-t-il d'opération élémentaires avant la boucle ?
Correct !
Exercice à réponse courte
Combien y'a-t-il d'opération élémentaires dans la boucle (en fonction du nombre N de notes) ?
Correct !
Exercice à réponse courte
Combien y'a-t-il d'opération élémentaires après la boucle (seulement dans la fonction) ?
Correct !
Exercice à réponse courte
Combien y'a-t-il d'opération élémentaires en tout (en fonction du nombre N de notes) ?
Correct !
Exercice à réponse courte
La complexité est elle linéaire ?
Correct !

un curseur délicat

Nous avons déjà traité la question de la recherche d'un caractère dans un texte. Nous allons ici traiter un problème assez similaire mais un peu plus délicat : chercher une chaine dans une autre. Pour plus de clarté, nous appelerons mot la chaine recherchée, et texte la chaine dans laquelle on effectue la recherche.

Commencez par regarder la vidéo ci-dessous pour comprendre le problème.

Ecrivons le pseudo code :

fonction cherchePattern(mot,texte) :
     pos -> -1
     idx -> 0
     tant que idx < len(texte)-len(mot) and pos = -1
          if texte[idx:idx+len(mot)] == mot : pos = idx
          idx = idx + 1
     fin de tant que
     renvoyer pos

Exercice de code : reverse avec pop

Construction d'une liste par ajout successifs

retourner une liste par ajout successifs

On veut retourner une liste (c'est à dire ranger ses éléments dans l'ordre inverse) et on va procéder par ajouter successifs (il existe d'autres façons de le faire).
L'algorithme est assez simple :

fonction retourner(lst) :
    lstReverse = [ ]
    tant que lst non vide :
        retirer le dernier elem de lst et l'ajouter à la fin de  lstReverse
    fin de pour
    renvoyer lstReverse
Coder ceci en python ne pose pas de grosse difficulté, mais il faut se souvenir de la méthode pop et de son usage....
Voici un code qui va te servir d'exemple pour l'exercice.

Rappel :
lst = [1,2,3]
a = lst.pop()
-> a=3 et maintenant lst=[1,2]
lst.pop() retire le dernier élément de la liste lst et renvoie sa valeur.
Exercice de code : reverse avec pop

Au lieu de append, on pourrait aussi utiliser une concaténation de liste : lstR = lstR + [val] donnera le même résultat, essaye les deux façons.
(attention : en réalité ces deux façon de procéder ne sont pas équivalentes. Elle donnent le même résultat et pour cette année nous n'entreront pas dans les détails sr la différence de traitement entre les deux)

On pourrait même ne rien ajouter et ne rien concaténer :

def reversePOP(lst: list ) -> list :
    lstR=[0] * len(lst) # initialise une liste avec len(lst) 0
    idx=0
    while len(lst) > 0:
        e=lst.pop()
        lstR[idx]=e
        idx+=1
    return lstR
Et là encore, le résultat est le même mais les opérations réalisées ne sont pas les même en réalités. Et ici aussi nous n'entreront pas cette année dans les détails.

Toutefois nous aurions put écrire aussi bien cet algorithme :

fonction retourner(lst) :
    lstReverse = [ ]
    tant que lst non vide :
        retirer le premier elem de lst et l'ajouter au début de  lstReverse
    fin de pour
    renvoyer lstReverse
Tu pourra coder ce second algorithme en utilisant lst.pop(0) qui retire l'élément d'indice 0 et lstR.insert(0,val) qui insère val en tête de liste.

On pourrait aussi utiliser une concaténation de liste : lstR = [val] + lstR donnera le même résultat, essaye les deux façons, et surtout remarque bien :

ajouter en tête : lst.insert(0,val) ou lst=[val] + lst
ajouter en queue : lst.append(val) ou lst=lst+[val]
retirer en tête : val = lst.pop(0)
retirer en queue :val = lst.pop()

Rappel :
lst = [1,2,3]
lst.insert(0,7)
-> Maintenant lst vaut [7,1,2,3]
Exercice de code : reverse avec insert

Ou avec l'autre façon, sans rien changer à l'algorithme, mais en remplaçant insert par une concaténation de liste :

Rappel :
lst = [1,2,3]
lst [7]+lst
-> Maintenant lst vaut [7,1,2,3]
Exercice de code : reverse sans pop et sans insert

Complexité

Peut tu estimer la complexité des codes de retournement ? Sont ils tous équivalent ?

Trier les éléments

Vous aller programmer ici une fonction tri(lst) qui va trier une liste. L'algorithme utilisé, que nous reverrons plus tard dans une autre forme, est le suivant :

fonction triInsertion(lst) :
    listTriee=[]
    Tant que longueur(lst) > 0 :
        rechercher l'indice du min dans lst
        retirer cet élément (avec pop) et l'ajouter (en queue) dans listeTrie
    fin de tant que
    renvoyer listeTriee
(la fonction idxMin(list) est disponible dans cet exercice)
Exercice de code

Dans ce code, que vous venez de faire, on a pas vraiment de curseurs (il y en a cependant un, caché dans la fnction idxMin que vous avez utilisé), d'accumulateur, ou de compteur. En effet ici on ne compte rien, on ne somme rien, et on ne localise rien.

L'ajout successif d'élément dans une liste est un autre outil indispensable que vous serez souvent amenés à utiliser.

Estimons la complexité de cet algorithme expérimentalement avec time().

Exemple

En raison de limitations sur ce site, il n'est pas pssible de travailler sur des listes très grandes. Néanmoins, ici, on a pris une séries de valeurs de N allant de 10 à 2560. A chaque fois on multiplie N par 2. Le temps de calcul évolue d'abord linéairement pour les petites valeurs de N mais rapidement on voit que quand N est multiplié par 2, le temps est multiplié par 4 (2² !)

La complexité semble donc plutot propotionelle à N² dans cet exemple.

Combien de fois est exécutée la boucle while ? Combien d'opération dans cette boucle while ?

La réponse est que la boucle while est exécutée N fois, mais dans la boucle, on appelle idxMin. idxMin a une complexité en O(N), mais comme la liste lst est raccourcie au fur et a mesure, c'est un peu compliqué....

Au premier tour, idxMin cherche dans une liste de longueur N

A second tour dans une liste de longueur N-1

Au troisième tour, dans une liste de longueur N-1

etc... jusqu'au dernier tour, ou il ne reste qu'un élément.

si le temps de idxMin est N, alors le temps de tout les appels est :

1 + 2 + ... + N = N(N+1)/2 = N² /2 + N/2

pour de grandes valeurs de N, N² >> N, la complexité sera proportionnelle à N². On parle ici de complexité quadratique.

S1 - Les fonctions

Définir une Fonction


La fonction valeur absolue

Nous allons commencer avec un exemple. Vous rappelez-vous de la fonction abs ? Elle prend seulement un argument (un nombre x), et retourne sa valeur absolue (qui devient x quand x ≥ 0 et -x quand x < 0). La façon de définir cette fonction dans Python est :

 
Exemple

Nous pourrions coder la même fonction différemment, sans que cela ne fasse aucune différence dans la façon de l'utiliser.

Dans cette seconde version nous introduisons 2 fois l'instruction return. Ne perdez pas de vue que, dès lors qu'une instruction return est exécutée, la fonction s'arrête (et on reprend le programme appelant là ou on l'avait arrêté).

Exemple

Notez que dans cette version nous n'initialisons pas la variable valeur absolue, c'est inutile, on n'utilise aucune variable, on renvoie simplement un résultat.

Exercices

Exercice 1 : Pythagore
Exercice de code : Pythagore
Ci dessous, donne ici une fonction qui teste si a^2 +b^2 == c^2 et qui affiche si le triangle est rectangle. Cette fonction ne renvoie rien (None).

Modifiez cette procédure pour la transformer en une fonction qui renvoie True si l'égalité est vraie et False sinon.

Vous devez modifier :
  • Le corps de la fonction pour renvoyer True ou False
  • La docstring et la ligne de la définition de la fonction
  • les appels pour que le programme principal affiche le résultat de la fonction.

Exercice 2 : multiple de 3

Exercice de code : Multiples de 3
Ci dessous une donne une fonction qui affiche les multiple de 3 jusqu'à 100.

Modifiez la fonction mult3 pour qu'elle affiche les multiples de 3 jusqu'à un entier MAX qui sera passé en paramètre.

Vous devez :
  • Modifier la définition de la fonction, pour passer un paramètre suplémentaire n_max
  • modifier le corps de la fonction pour n\'afficher les multiples de 3 que jusqu'à n_max
  • modifier la docstring
Le correcteur va générer un entier n_max pour exécuter et tester la fonction.

Exercice 3 : puissance
Exercice de code : Puissance
Ecrire une fonction qui prend 2 arguments a et k et qui renvoie la valeur de a^k .

Vous devez :
  • complétez la définition de la fonction, en ajoutant les paramètres et le type de la sortie
  • écrire le corps de la fonction
  • écrire la docstring
Vous ,
Exercice 4 : plus grande valeur
Exercice de code : Plus grande valeur
Ecrire une fonction qui renvoie la plus grande de 2 valeurs entières passées en paramètres.

Vous placerez des appels avec ces valeurs comme exemple pour tester :
plusGrandeValeur(4, 9) renverra 9
plusGrandeValeur(2, 1) renverra 2
Exercice 5 : Vitesse moyenne
Exercice de code : Vitesse Moyenne
Ecrire une fonction qui calcule la vitesse moyenne d'une voiture, connaissant son temps de parcours (en heures) et la distance parcourue (en km)

Ex: vitesseMoyenne(4, 300) renverra 75
Le programme principal affichera 75 km/h

Bonnes pratiques de programmation

Préciser le typage de chacun des paramètres

Le langage Python est plus aisé pour démarrer la programmation pour la concision des codes écrits et pour la gestion automatique du typage par l'interpréteur. Cependant, le but est que vous puissiez à terme être capable de faire basculer vos compétences acquises en NSI sur Python vers d'autres langages de programmation.

Comme la plupart des langages de programmation nécessitent la spécification du typage des variables, on vous demandera d'écrire en Python, une fonction en précisant le type de chaque entrée et sortie en suivant le même formalisme ci-dessous :

def nomFonction(argument: type) -> typeRetour:
		blocs des instructions
		return résultat
	
Exemple : Typer les arguments et les résultats
Exemple : ici on précise dans la définition que le paramètre x est float et que la fonction renvoie aussi un float.

Nommage

La convention PEP8 donne l'habitude de nommer les fonctions (comme les variables) avec des lettres minuscules et des tirets bas (celui du "8") _.


Exemples : lire_fichier, resoudre_equation, creer_grille_vide etc...

Comme pour les noms de variables, il est absolument recommandé de ne pas utiliser de caractères accentués dans les noms des fonctions.


On préfère toutefois parfois (ou souvent suivant les personnes) la convention dite camelCase qui consiste a écrire en minuscules, mais si le nom est constitué de plusieurs mots, on met une majuscules à tous les mots sauf le premier. Exemples : lireFichier, resoudreEquation, creerGrilleVide etc...

Pour clarifier la fonction, il est conseillé d'utiliser un verbe dans son nom (obtenir, donner, get, set, ...).

Documenter ses fonctions

Il est important de documenter vos fonctions, c'est-à-dire de décrire en quelques phrases le rôle de la fonction, de donner des informations sur la fonction, le lien entre les entrées et la sortie.

Pour cela, juste en dessous de la première ligne définissant la fonction, il suffit de mettre ses informations de préférence entre """ """ ou entre''' ''' et ''' ; c'est ce que l'on appelle en franglais le docstring de la fonction).
Dans la docstring vous indiquerez ce que sont les paramètres et ce que renvoi la fonction, sous cette forme :

Exemple
Documenter une fonction, accéder à la documentation

L'intérêt de l'auto-documentation d'une fonction par un texte est double :

  • Pour vous : le faire vous oblige à réfléchir au contenu de votre fonction avant de la programmer ; c'est un gain d'efficacité,
  • Pour les utilisateurs de votre code (ou pour vous longtemps après avoir programmé la fonction) : Quand on saisit dans la console, après l'exécution de la fonction, l'instruction help(nom de la fonction), Python affiche le docstring de la fonction ce qui nous permet d'avoir des informations sur la fonction en cas d'oubli.

A faire seulement après avoir étudié les listes : fonctions traitant des listes

Utiliser un compteur ou un accumulateur

Dans de nombreux cas, on doit :

  • compter le nombre d'occurrences d'une condition
  • sommer une quantité
  • faire un produit de façon répétée

Dans ces cas, on utilisera un compteur ou un accumulateur.

Multiples de 3

Un compteur en action

Ecrire une fonction qui prend en argument une liste de nombres entiers et renvoie le nombre de multiples de 3 dans cette liste

Exercice de code : Compte les multiples de 3
Ecrire la fonction compterMult3(lst). Une liste lst sera générée pour tester votre code.
Calcul de la moyenne
Exercice de code : Calcul de moyenne
Ecrire la fonction moyenne(lst). Une liste lst sera générée pour exécuter votre code.
Détermination de la médiane

Déterminer la médiane d'une série statistique

Rappel de l'algorithme de la médiane

Soit lst=[x1, x1, ...xN] une série de nombres (la série contient N éléments) ordonnée dans l'ordre croissant.

  • Si N est pair la médiane est la moyenne des valeurs de rang N/2 et N/2 + 1
  • Si N est impair, la médiane est la valeur de rang (N+1)/2
Exercice de code : Déterminer la médiane
Ecrire une fonction qui prend en argument une liste de nombre triée en ordre croissant, et renvoie la médiane de la liste. Une liste lst sera générée pour exécuter votre code.

1ere - Algo - TD2

Boucles imbriquées

Les algorithmes que nous avons vus jusqu'ici utilisent pour la plupart une boucle for.

Dans les exercices ci-dessous, nous allons utiliser des boucles imbriquées : des boucles dans des boucles.

Algorithme de mélange Knuth
Il est souvent nécessaire de mélanger les éléments d'une liste aléatoirement, c'est par exemple le cas si vous simulez un jeu de cartes, et que vous voulez distribuer les cartes. Il existe de nombreux algorithmes pour cela, nous allons étudier l'algorithme de mélange de Knuth.
  • on parcours le tableau de gauche à droite
  • Pour chaque élément d'indice i, on le permute avec l'élément d'indice j avec j aléatoire entre 0 et i
Ecrire une fonction melangeKnuth(l) qui réalise la permutation aléatoire d'un tableau l avec l'algorithme de Knuth. La fonction renvoie la liste ainsi mélangée.
Exercice de code : Méli-Mélo de Knuth
Ecrire la fonction melangeKnuth(lst). Une liste lst sera générée pour tester votre code.
Allumer Eteindre

Vous devez écrire un code qui représente la situation, et qui affiche a liste des lampes allumées après la 100ème étape.
L'état d'une lampe sera représenté par True (allumé) ou False (éteint).
Commencez par créer un tableau de 100 booléen tous égaux à True, c'est l'état après l'étape 1.
Ensuite vous devez effectuer les étape 2 à 100 (inclues). Durant chaque étape, vous devez changer l'état des lampes qui conviennent. Par exemple à l'étape 2, toutes les lampes paires, etc...
Enfin, un dernier parcours de la liste des lampes sera fait pour afficher les n° des lampes allumées
Exercice de code : Allumée ?
Les lampes étiente peuvent être allumées à l'étape suivante. A chaque étape on manipule les interupteurs, donc on rallume des lampes éteintes ou éteint des lampes allumées....

Série d'exercice portant sur l'utilisation du Tant que

L'usage des boucles while peut poser d'autres problèmes que ceux vus précédemment. Voyons cela sur des exemples :

Le lièvre et la tortue (partie 1)

Dans cet exercice vous allez programmer une simulation d'une course entre le lièvre et la tortue.

Les règles du jeu :

On jette un dé à 6 faces. Si on obtient 6, le lièvre à gagné, sinon, la tortue avance d'une case. La tortue gagne si elle atteint la 4ème case, les deux partent de la case 0.

Vous devez écrire la fonction game() qui renvoie "Lievre" ou "Tortue".

Exercice de code : Le lièvre et la tortue
Ecrire une function game() qui simule une course avec les règles ci-dessus et renvoie le vainqueur : "Lievre" ou "Tortue". Lors de l'exécution le solver va générer une variable x utile pour gérer le comportement de random, n'en tenez aucun compte.
Le lièvre et la tortue (partie 2)

Dans cette seconde partie, on admet que vous disposez de la fonction game() de l'exercice précédent. Vous allez l'utiliser pour déterminer qui, du Lièvre et de la Tortue, a les meilleures chances de gagner la course.

Pour le savoir, écrire un code qui appelle 1000 fois la fonction game() et qui affiche le pourcentage de victoires de la Tortue, arrondi à 0.1 près (utiliser round() ).

Exercice de code : Le lièvre et la tortue (partie 2)
Ecrire un programme qui appelle 1000 fois la fonction game() de la partie 1, et compte le nombre de victoires de la Tortue. Votre code doit afficher le pourcentage de victoire de la Tortue. Lors de l'exécution le solver va générer une variable x utile pour gérer le comportement de random, n'en tenez aucun compte.

Ce dernier code cache une boucle imbriquée dans le boucle. Combien de fois appelle t-on game() ? Si on admet qu'une partie se joue en moyenne en 4 lancés de dé, combien de fois les 1000 courses ont nécessité le lancé du dé ?

 
Le duc de Toscane

Il est naturellement possible d'expliquer le paradoxe du Duc de Toscane en calculant les probabilités d'obtenir 10 ou 9. Mais nous allons le faire d'une autre façon : en effectuant des simulations numériques.

La première chose à faire est de créer une fonction play() qui simule une partie.

Dans un second temps, nous écrirons un code qui appelle un grand nombre de fois cette fonction play() et compte le nombre de 10 et de 9 obtenus.

On arrêtera lorsque le nombre de 9 + nombre de 10 sera égal à 1000 comme si nous jouions un grand nombre de parties.

Exercice de code
Ecrire la fonction play : Entrée : Rien Sortie : La somme de trois dés (3 entiers aléatoires entre 1 et 6)

Maintenant vous devez écrire un code qui appelle play() tant que le nombre de résultats 9 ou 10 n'est pas 1000.

Exercice de code
Ecrire un code qui appelle la fonction play() (inutile de la réécrire elle est préprogrammée dans l'exercice).

Vous devez compter le nombre de fois ou on obtient 9 et le nombre de fois ou on obtient 10.
On continue de jouer tant que le nombre total de 9 et de 10 n'atteint pas 1000.
 
Vous utiliserez n9 et n10 comme compteurs.