python exercices listes

Identification

Infoforall

13 - Exercices sur les tableaux


Cette activité est composée de plusieurs exercices qui visent à exploiter et réviser les notions vues jusqu'à présent.

Attention : on rappelle que les tableaux qui nous utilisons dans Python sont en réalité des objets de type list.

Nous utiliserons donc les lists de python comme des tableaux (arrays en anglais).

Cette activité vous permettra de maitriser les tableaux avec assez de recul pour aborder le projet Tkinter de l'activité suivante, où vous aurez à réaliser un petit jeu graphique.

Logiciel nécessaire pour l'activité : Python 3 : Thonny, IDLE ...

Evaluation ✎ : nada, tous les exercices sont corrigés. Par contre, il y a le DS qui va bien derrière :o)

1 - Fonction

01° Compléter la fonction ci-dessous pour qu'elle renvoie la bonne valeur. Elle devra contenir un test conditionnel.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
def signe(x) : '''Renvoie 1 si x est positif, -1 s'il est négatif et 0 s'il est nul :: param x(int) :: un entier relatif :: return (int) :: 1 si > 0, -1 si < 0 et 0 si nul :: exemple :: >>> signe(10) 1 >>> signe(-10) -1 >>> signe(0) 0 ''' return 0 if __name__ == '__main__' : import doctest doctest.testmod()

Tester avec quelques appels de la fonction dans le Shell une fois la fonction en mémoire.

>>> signe(45) 1 >>> signe(-125) -1

...CORRECTION...

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
def signe(x) : '''Renvoie 1 si x est positif, -1 s'il est négatif et 0 s'il est nul :: param x(int) :: un entier relatif :: return (int) :: 1 si > 0, -1 si < 0 et 0 si nul :: exemple :: >>> signe(10) 1 >>> signe(-10) -1 >>> signe(0) 0 ''' if x > 0 : return 1 elif x < 0 : return -1 else : return 0 if __name__ == '__main__' : import doctest doctest.testmod()

02° Sans supprimer la fonction de la question 1, rajouter et compléter la fonction ci-dessous pour qu'elle renvoie la bonne valeur du polynôme d'ordre 3. Elle n'a pas besoin de contenir de boucle. Il suffit de calculer la bonne valeur et de renvoyer la réponse.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
def polynome(a,b,c,d,x) : '''Renvoie le calcul pour x du polynôme ax*x*x + b*x*x + c*x + d :: param a(int) :: valeur de a :: param b(int) :: valeur de b :: param c(int) :: valeur de c :: param d(int) :: valeur de d :: param x(int) :: valeur à laquelle on veut calculer le polynôme :: exemple :: >>> polynome(1,1,1,1,2) 15 ''' return 0 if __name__ == '__main__' : import doctest doctest.testmod()

...CORRECTION...

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
def polynome(a,b,c,d,x) : '''Renvoie le calcul pour x du polynôme ax*x*x + b*x*x + c*x + d :: param a(int) :: valeur de a :: param b(int) :: valeur de b :: param c(int) :: valeur de c :: param d(int) :: valeur de d :: param x(int) :: valeur à laquelle on veut calculer le polynôme :: exemple :: >>> polynome(1,1,1,1,2) 15 ''' return a*x**3 + b*x**2 + c*x+ d if __name__ == '__main__' : import doctest doctest.testmod()

03° Placer les deux fonctions en mémoire. Nous allons maintenant chercher à connaître le signe du polynome 5x3 - 3x2 + 20x -8 pour différentes valeurs de x. Il suffit donc d'utiliser les deux fonctions à la fois.

>>> signe( polynome(5,-3,20,-8,100) )

04° Compléter la fonction ci-dessous pour qu'elle corresponde à la documentation et aux doctests. Il faudra utiliser une boucle bornée FOR et un compteur temporaire qu'on aura initialisé à 0 au départ.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
def somme_carre(n) : '''Renvoie la somme de 1 + 4 + 9 + 16 + ... jusqu'à n*n inclus :: param n(int) :: un entier supérieur ou égal à 1 :: return (int) :: la somme voulue :: exemples :: >>> somme_carre(3) 14 >>> somme_carre(4) 30 ''' return 0 if __name__ == '__main__' : import doctest doctest.testmod()

Tester votre fonction avec des valeurs inconnues dans le Shell après avoir lancé le programme et placé la fonction en mémoire.

>>> somme_carre(5) >>> somme_carre(50)

...CORRECTION...

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
def somme_carre(n) : '''Renvoie la somme de 1 + 4 + 9 + 16 + ... jusqu'à n*n inclus :: param n(int) :: un entier supérieur ou égal à 1 :: return (int) :: la somme voulue :: exemples :: >>> somme_carre(3) 14 >>> somme_carre(4) 30 ''' compteur = 0 for x in range(n+1) : compteur = compteur + x*x return compteur if __name__ == '__main__' : import doctest doctest.testmod()

2 - Lecture d'un tableau

Nous allons revoir ici l'interaction entre fonction et tableau.

Commençons par la lecture un à un d'éléments d'un tableau de façon à compter le nombre d'éléments négatifs.

05° Compléter la fonction compter ci-dessous pour qu'elle corresponde à la documentation et aux doctests.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
def compter(entree) : '''Fonction qui renvoie le nombre de nombres négatifs trouvés dans le tableau-paramètre entree :: param entree(list) :: un tableau ne contenant que des nombres entiers :: return (int) :: le nombre de nombres négatifs trouvés dans entree :: exemple :: >>> compter([1,-10,5,-2,6]) 2 >>> compter([1,10,5,2,6]) 0 ''' nombre = 0 return nombre if __name__ == '__main__' : import doctest doctest.testmod() tableau_test = [10,-2,-3,-4] reponse = compter(tableau_test)

...CORRECTION...

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
def compter(entree) : '''Fonction qui renvoie le nombre de nombres négatifs trouvés dans le tableau-paramètre entree :: param entree(list) :: un tableau ne contenant que des nombres entiers :: return (int) :: le nombre de nombres négatifs trouvés dans entree :: exemple :: >>> compter([1,-10,5,-2,6]) 2 >>> compter([1,10,5,2,6]) 0 ''' nombre = 0 for element in entree : if element < 0 : nombre = nombre + 1 return nombre if __name__ == '__main__' : import doctest doctest.testmod() tableau_test = [10,-2,-3,-4] reponse = compter(tableau_test)

06° Modifier la fonction compter ci-dessous pour qu'elle corresponde à la documentation et aux doctests : on lui fournit maintenant un deuxième paramètre seuil qui ne correspond pas nécessairement à 0.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
def compter(entree, seuil) : '''Fonction qui renvoie le nombre de nombres strictement inférieur à seuil trouvés dans le tableau-paramètre entree :: param entree(list) :: un tableau ne contenant que des nombres entiers :: param seuil(int) :: la valeur du seuil à surveiller :: return (int) :: le nombre de nombres strictement inférieurs au seuil trouvés dans entree :: exemple :: >>> compter([1,-10,5,-2,6],5) 3 >>> compter([1,10,5,2,6], 4) 2 ''' nombre = 0 for element in entree : if element < 0 : nombre = nombre + 1 return nombre if __name__ == '__main__' : import doctest doctest.testmod() tableau_test = [10,-2,-3,-4] reponse = compter(tableau_test, 5)

...CORRECTION...

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
def compter(entree, seuil) : '''Fonction qui renvoie le nombre de nombres strictement inférieur à seuil trouvés dans le tableau-paramètre entree :: param entree(list) :: un tableau ne contenant que des nombres entiers :: param seuil(int) :: la valeur du seuil à surveiller :: return (int) :: le nombre de nombres strictement inférieurs au seuil trouvés dans entree :: exemple :: >>> compter([1,-10,5,-2,6],5) 3 >>> compter([1,10,5,2,6], 4) 2 ''' nombre = 0 for element in entree : if element < seuil : nombre = nombre + 1 return nombre if __name__ == '__main__' : import doctest doctest.testmod() tableau_test = [10,-2,-3,-4] reponse = compter(tableau_test, 5)

3 - Renvoyer un nouveau tableau

Revoyons maintenant comment renvoyer un nouveau tableau à partir d'un tableau fourni en entrée.

Dans l'exercice suivant, il faudra lire les éléments d'un tableau fourni en entrée de la fonction et renvoyer un tableau contenant des éléments valant le double des éléments du tableau d'entrée.

07° Modifier la fonction doubler ci-dessous pour qu'elle corresponde à la documentation et aux doctests. Pour l'instant, elle parvient à créer un tableau vide et lire un à un les numéros d'index disponibles pour les deux tableaux.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
def doubler(entree) : '''Fonction qui renvoie un tableau où chaque élément est le double de l'élément correspondant du tableau entrée :: param entree(list) :: un tableau ne contenant que des nombres entiers :: return (list) :: le tableau où chaque élément est le double de l'élément du même index dans entree :: exemple :: >>> doubler([1,2,3,4]) [2, 4, 6, 8] ''' reponses = [None for valeur in entree] for index in range(len(entree)) : pass # Il faudra que chaque élément de réponses à cet index soit le double de celui d'entree à cet index return reponses if __name__ == '__main__' : import doctest doctest.testmod() tableau_test = [10,-2,-3,-4] table_reponse = doubler(tableau_test)

...CORRECTION...

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
def doubler(entree) : '''Fonction qui renvoie un tableau où chaque élément est le double de l'élément correspondant du tableau entrée :: param entree(list) :: un tableau ne contenant que des nombres entiers :: return (list) :: le tableau où chaque élément est le double de l'élément du même index dans entree :: exemple :: >>> doubler([1,2,3,4]) [2, 4, 6, 8] ''' reponses = [None for valeur in entree] for index in range(len(entree)) : reponses[index] = entree[index] * 2 return reponses if __name__ == '__main__' : import doctest doctest.testmod() tableau_test = [10,-2,-3,-4] table_reponse = doubler(tableau_test)
Déclaration de tableau par compréhension

La déclaration d'une liste par déclaration est celle que nous utilisons déjà depuis quelques lignes pour créer un tableau vide ayant le même nombre d'éléments que le tableau d'origine :

reponses = [None for valeur in entree]
>>> tab1 = [1, 2, 3] >>> sortie = [None for element in tab1] >>> sortie [None, None, None]

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

Si le code suivant est similaire aux lignes 12 à 15 de la correction de la question précédente !

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

C'est beaucoup plus simple à écrire. Attention, en réalité, l'interpréteur Python réalise donc en arrière plan une boucle for. Cela revient bien au code qu'on a fourni sur la correction précédente.

Nous allons finir cette partie avec un cas typique : la multiplication d'éléments de même index pour créer un nouveau tableau.

Nous allons voir ceci avec le cas simple de la distance parcourue lorsqu'on se déplace à une vitesse constante pendant une duree précise.

Si on se déplace à 5 m.s pendant 10 secondes, on aura ainsi parcouru une distance ed 50m. (5*10 pour ceux qui ne suivent pas !)

Nous allons créer une fonction dont les paramètres sont deux tableaux : l'un contient la vitesse et l'autre la durée pendant laquelle la vitesse est restée constante.

Imaginons qu'on se déplace à 9 m.s-1 pendant 4s puis à 3 m.s-1 pendant 120s puis à 8 m.s-1 pendant 10s.

On aurait à taper :

>>> vitesses = [9, 3, 8] >>> durees = [4, 120, 10]

On pourrait alors créer un tableau distances contenant ceci :

>>> distances = [36, 360, 80]

Il faudra donc écrire un code en boucle du type distances[index] = vitesses[index] * durees[index]...

Il faudra donc une boucle FOR avec index.

08° Modifier la fonction multiplier ci-dessous pour qu'elle corresponde à la documentation et aux doctests. Elle doit fournir en sortie un tableau dont les éléments sont pour chaque index la multiplication des éléments de même index des deux tableaux d'entrée.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
def multiplier(entree1, entree2) : '''Fonction qui renvoie un tableau où chaque index est la multiplication des mêmes index dans les tableaux entree1 et entree2 :: param entree1(list) :: un tableau ne contenant que des nombres entiers :: param entree2(list) :: un tableau ne contenant que des nombres entiers :: return (list) :: le tableau où chaque élément est la multiplication des deux index des tableaux entree1 et entre2 .. CU :: (conditions d'utilisation) les deux tableaux doivent comporter le même nombre d'éléments ! :: exemple :: >>> multiplier([9,3,8], [4,120,10]) [36, 360, 80] ''' multiplications = [None for valeur in entree1] for index in range(len(entree1)) : pass # A vous de gérer la multiplication return multiplications if __name__ == '__main__' : import doctest doctest.testmod()

...CORRECTION...

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
def multiplier(entree1, entree2) : '''Fonction qui renvoie un tableau où chaque index est la multiplication des mêmes index dans les tableaux entree1 et entree2 :: param entree1(list) :: un tableau ne contenant que des nombres entiers :: param entree2(list) :: un tableau ne contenant que des nombres entiers :: return (list) :: le tableau où chaque élément est la multiplication des deux index des tableaux entree1 et entre2 .. CU :: (conditions d'utilisation) les deux tableaux doivent comporter le même nombre d'éléments ! :: exemple :: >>> multiplier([9,3,8], [4,120,10]) [36, 360, 80] ''' multiplications = [None for valeur in entree1] for index in range(len(entree1)) : multiplications[index] = entree1[index] * entree2[index] return multiplications if __name__ == '__main__' : import doctest doctest.testmod()

Resterait à créer une fonction somme qui renvoie automatiquement la somme des éléments contenus dans un tableau d'entier. On pourra ainsi obtenir la distance parcourue même sur parcours réel. Il suffit d'avoir la vitesse toutes les secondes par exemple. C'est long pour un humain, très facile pour un ordinateur.

Vous pourriez ainsi répondre la fonction de la question 05 et l'appliquer sur votre tableau des distances. La sortie de votre fonction donnerait la distance parcourue au total. Pas mal non ?

4 - Modification de tableaux

Nous avons vu que les tableaux sont mutables. Si on veut modifier le contenu d'un tableau dans une fonction, il suffit donc d'avoir son identifiant.

On pourrait modifier directement ainsi un tableau défini dans une variable globale mais nous allons plutôt toujours passer le tableau en paramètre.

Pourquoi ?

Premièrement, cela rend le code testable avec les doctests plus facilement.

Deuxièmement, cela rend le code plus solide à la modification.

Le seul moment où nous utiliserons pour l'instant les variables globales est dans les fonctions événements car on ne peut pas facilement leur passer de paramètres hormis le paramètre d'événement. Mais même là, on peut s'en passer en réalité.

Voici un exemple de fonction qui modifie un tableau en multipliant les valeurs par 60 : ca peut être utile pour un tableau de durées exprimées en minutes alors qu'on veut des secondes.

09° Modifier la fonction multiplier ci-dessous pour qu'elle corresponde à la documentation et aux doctests. Cette fois, on ne renvoie pas de tableau, on doit modifier le tableau mutable reçu en paramètre entree.

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

...CORRECTION...

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

Dernier point : il est possible que seul un élément ayant un index précis doive être modifié.

10° Modifier la fonction multiplier_un_element qui reçoit maintenant un nouveau paramètre : le numero d'index unique sur lequel on va agir. Il faudra donc supprimer la boucle FOR et insérer d'une façon ou d'une autre un test conditionnel. Voir le doctest pour voir comment la fonction doit fonctionner.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
def multiplier_un_element(entree, coefficient, numero) : '''PROCEDURE qui modifie l'élement d'index numero du tableau entree en multipliant sa valeur par le coefficient fourni :: param entree(list) :: un tableau ne contenant que des nombres entiers :: param coefficient(int) :: un entier servant de coefficient multiplicateur :: param numero(int) :: l'index de l'élément à cibler .. Effet de bord :: le paramètre entree est modifié par la procédure :: exemple :: >>> tab_test = [1,2,10] >>> multiplier_un_element(tab_test, 60, 2) >>> tab_test [1, 2, 600] ''' pass if __name__ == '__main__' : import doctest doctest.testmod()

...CORRECTION...

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
def multiplier_un_element(entree, coefficient, numero) : '''PROCEDURE qui modifie l'élement d'index numero du tableau entree en multipliant sa valeur par le coefficient fourni :: param entree(list) :: un tableau ne contenant que des nombres entiers :: param coefficient(int) :: un entier servant de coefficient multiplicateur :: param numero(int) :: l'index de l'élément à cibler .. Effet de bord :: le paramètre entree est modifié par la procédure :: exemple :: >>> tab_test = [1,2,10] >>> multiplier_un_element(tab_test, 60, 2) >>> tab_test [1, 2, 600] ''' entree[numero] = entree[numero] * 60 if __name__ == '__main__' : import doctest doctest.testmod()

Activité publiée le 07 12 2019
Dernière modification : 29 05 2020
Auteur : ows. h.