[go: up one dir, main page]

Aller au contenu

Programmation Python/Listes

Un livre de Wikilivres.

Les listes sont des séquences, des collections ordonnées d'objets séparés par des virgules. On les déclare avec l'opérateur d'indiçage ([]) :

>> maListe = ['a','b','c']
>> maListe
['a','b','c']

Comme les caractères dans une chaîne, les objets placés dans une liste sont rendus accessibles par l'intermédiaire d'un index (un nombre qui indique l'emplacement de l'objet dans la séquence, à partir de zéro). De plus, le slicing (« découpage en tranches ») permet aussi de dégager une sous-liste en précisant deux index correspondant aux bornes de la plage.

Une sortie indicée donne :

>> maListe[0]
'a'

>> maListe[-1]
'c'

Une séquence donne par slicing :

>> maListe[0:2]
['a','b']

>> maListe[1:]
['b','c']

Les éléments qui constituent une liste peuvent être de types variés :

>>> jour = ['lundi', 'mardi', 'mercredi', 'jeudi', 'vendredi', 476, 3.142]
>>> print(jour)
['lundi', 'mardi', 'mercredi', 'jeudi', 'vendredi', 476, 3.142]

Dans cet exemple, en effet, les premiers éléments sont des chaînes de caractères, puis il y a un entier et un réel. À cet égard, le concept de liste est donc différent des tableaux (array) que l'on rencontre les langages de programmation de bas niveau, où tous les éléments doivent être du même type.

Vous pouvez aisément déterminer si un élément fait partie d'une liste à l'aide de l'instruction in :

 print("a" in ["a", "b", "c"])      # True
 print(not "a" in ["a", "b", "c"])  # False

Si l'emplacement de l'élément importe dans la liste :

 print ["a", "b", "c"].index("a") == 0 # True
 print ["a", "b", "c"].index("z")      # ValueError

À la différence de ce qui se passe pour les chaînes, qui constituent un type de données non-modifiables, il est possible de changer les éléments individuels d'une liste :

>>> jour = ['lundi', 'mardi', 'mercredi', 'jeudi', 'vendredi', 476, 3.142]
>>> jour[5] = jour[5] + 1016
>>> print(jour)
['lundi', 'mardi', 'mercredi', 'jeudi', 'vendredi', 1492, 3.142]

Les exemples ci-dessus devraient attirer votre attention sur le fait qu'une tranche découpée dans une liste est toujours elle-même une liste (même s'il s'agit d'une tranche qui ne contient qu'un seul élément), alors qu'un élément isolé peut contenir n'importe quel type de donnée.

Exemple en deux dimensions :

>>> jour = ['lundi', 'mardi', 'mercredi', 'jeudi', 'vendredi', ['samedi matin', 'samedi après-midi', 'samedi soir'], 'dimanche']
>>> jour[5][0] = "samedi midi"
>>> jour
>>> jour = ['lundi', 'mardi', 'mercredi', 'jeudi', 'vendredi', ['samedi midi', 'samedi après-midi', 'samedi soir'], 'dimanche']

Ainsi, dans l'exemple ci-dessus on remplace le premier élément d'une liste (n° 0), qui est elle-même l'élément n° 5 d'une autre liste.

On peut appliquer aux listes les opérateurs + (concaténation) et * (multiplication) :

>>> fruits = ['orange','citron']
>>> legumes = ['poireau','oignon','tomate']
>>> fruits + legumes
['orange', 'citron', 'poireau', 'oignon', 'tomate']
>>> fruits * 3
['orange', 'citron', 'orange', 'citron', 'orange', 'citron']

L'opérateur * est particulièrement utile pour créer une liste de "n" éléments identiques :

>>> sept_zeros = [0]*7
>>> sept_zeros
[0, 0, 0, 0, 0, 0, 0]

Techniques de slicing avancées pour modifier une liste

[modifier | modifier le wikicode]

Insertion d'un ou plusieurs éléments n'importe où dans une liste :

>>> mots = ['jambon', 'fromage', 'confiture', 'chocolat']
>>> mots[2:2] = ["miel"]
>>> mots
['jambon', 'fromage', 'miel', 'confiture', 'chocolat']
>>> mots[5:5] = ['saucisson', 'ketchup']
>>> mots
['jambon', 'fromage', 'miel', 'confiture', 'chocolat', 'saucisson', 'ketchup']

Pour utiliser cette technique, vous devez prendre en compte les particularités suivantes :

  • Si vous utilisez l'opérateur [ ] à la gauche du signe égale pour effectuer une insertion ou une suppression d'élément(s) dans une liste, vous devez obligatoirement y indiquer une « tranche » dans la liste cible (c'est-à-dire deux index réunis par le symbole ":"), et non un élément isolé dans cette liste.
  • L'élément que vous fournissez à la droite du signe égale doit lui-même être une liste. Si vous n'insérez qu'un seul élément, il vous faut donc le présenter entre crochets pour le transformer d'abord en une liste d'un seul élément. Notez bien que l'élément mots[1] n'est pas une liste (c'est la chaîne fromage), alors que l'élément mots[1:3] en est une.

Suppression / remplacement d'éléments :

>>> mots[2:5] = []                       # [] désigne une liste vide
>>> mots
['jambon','fromage','saucisson', 'ketchup']
>>> mots[1:3] = ['salade']
>>> mots
['jambon', 'salade', 'ketchup']
>>> mots[1:] = ['mayonnaise', 'poulet', 'tomate']
>>> mots
['jambon', 'mayonnaise', 'poulet', 'tomate']
  • À la première ligne de cet exemple, nous remplaçons la tranche [2:5] par une liste vide, ce qui correspond à un effacement.
  • À la quatrième ligne, nous remplaçons une tranche par un seul élément. (Notez encore une fois que cet élément doit lui-même être « présenté » comme une liste).
  • À la 7e ligne, nous remplaçons une tranche de deux éléments par une autre qui en comporte 3.

Pour obtenir la différence entre deux listes :

a = ['jambon','fromage','saucisson', 'ketchup']
b = ['jambon', 'mayonnaise', 'poulet', 'tomate']
print([item for item in a if item not in b])
# ['fromage', 'saucisson', 'ketchup']

Pour l'intersection entre deux listes (en préservant l'ordre des éléments y compris leurs doublons), on applique la différence de la différence :

a = ['jambon','fromage','saucisson', 'ketchup']
b = ['jambon', 'mayonnaise', 'poulet', 'tomate']
dif = [item for item in a if item not in b]
print [item for item in a if item not in dif]
# ['jambon']

Considérons que vous disposez d'une liste fable que vous souhaitez recopier dans une nouvelle variable que vous appellerez phrase. La première idée qui vous viendra à l'esprit sera certainement d'écrire une simple affectation telle que :

>>> phrase = fable

En procédant ainsi, sachez que vous ne créez pas une véritable copie. À la suite de cette instruction, il n'existe toujours qu'une seule liste dans la mémoire de l'ordinateur. Ce que vous avez créé est seulement une nouvelle référence vers cette liste. Essayez par exemple :

>>> fable = ['Je','plie','mais','ne','romps','point']
>>> phrase = fable
>>> fable[4] ='casse'
>>> phrase
['Je', 'plie', 'mais', 'ne', 'casse', 'point']

Si la variable phrase contenait une véritable copie de la liste, cette copie serait indépendante de l'original et ne devrait donc pas pouvoir être modifiée par une instruction telle que celle de la troisième ligne, qui s'applique à la variable fable. Vous pouvez encore expérimenter d'autres modifications, soit au contenu de fable, soit au contenu de phrase. Dans tous les cas, vous constaterez que les modifications de l'une sont répercutées dans l'autre, et vice-versa.

En fait, les noms fable et phrase désignent tous deux un seul et même objet en mémoire. Pour décrire cette situation, les informaticiens diront que le nom phrase est un alias du nom fable.

Schéma de la copie d'une liste.
Schéma de la copie d'une liste.

Nous verrons plus tard l'utilité des alias. Pour l'instant, nous voudrions disposer d'une technique pour effectuer une véritable copie d'une liste. Avec les notions vues précédemment, vous devriez pouvoir en trouver une par vous-même.

 Python vous autorise à « étendre » une longue instruction sur plusieurs lignes, si vous continuez à encoder quelque chose qui est délimité par une paire de parenthèses, de crochets ou d'accolades. Vous pouvez traiter ainsi des expressions parenthésées, ou encore la définition de longues listes, de grands tuples ou de grands dictionnaires. Le niveau d'indentation n'a pas d'importance : l'interpréteur détecte la fin de l'instruction, là où la paire syntaxique est refermée.

Cette fonctionnalité vous permet d'améliorer la lisibilité de vos programmes. Exemple :

couleurs = ['noir', 'brun', 'rouge',
            'orange', 'jaune', 'vert',
            'bleu', 'violet', 'gris', 'blanc']


Sous Python, les listes sont des objets à part entière, et vous pouvez donc leur appliquer un certain nombre de méthodes particulièrement efficaces, après l'opérateur "." :

>>> nombres = [17, 38, 10, 25, 72]

>>> nombres.sort()                 # trier la liste
>>> nombres
[10, 17, 25, 38, 72]

>>> nombres.append(12)             # ajouter un élément à la fin
>>> nombres
[10, 17, 25, 38, 72, 12]

>>> nombres.reverse()              # inverser l'ordre des éléments
>>> nombres
[12, 72, 38, 25, 17, 10]

>>> nombres.index(17)              # retrouver l'index d'un élément
4

>>> nombres.remove(38)             # enlever (effacer) un élément
>>> nombres
[12, 72, 25, 17, 10]

append() (ajouter) : l'exemple suivant qui fait appel à la méthode "append" de l'objet "liste" (déclarée vide) illustre ce concept.

Il s'agit de remplir la hotte du Père Noël.

 #!/usr/bin/python
 # -*- coding: iso8859-1 -*-
 
 # on prépare une liste encore vide
 cadeaux = []
 
 # on va ajouter des éléments à la liste
 unCadeau = ""
 
 # la suite des éléments à introduire dans la liste est définie par l'utilisateur
 # lorsqu'il a terminé, l'utilisateur indique le mot "fin" qui ne sera pas introduit dans la liste
 while unCadeau <> "fin":
 	unCadeau = raw_input ("Père Noël, je voudrais que tu m'apportes ")
        # si l'utilisateur n'a pas frappé "fin", le mot est ajouté à la liste
 	if unCadeau <> "fin":
 		cadeaux.append(unCadeau)
 
 # finalement, on écrit la suite des éléments introduits dans la liste
 for chaqueCadeau in cadeaux:
 	print chaqueCadeau

split() : convertit une chaîne en une liste de sous-chaînes. On peut choisir le caractère séparateur en le fournissant comme argument, sinon c'est un espace, par défaut.

>>> chaine ="Votez pour moi"
>>> tableau = chaine.split()
>>> print tableau
['Votez', 'pour', 'moi']

>>> chaine = "Cet exemple, parmi d'autres, peut encore servir"
>>> chaine.split(",")
['Cet exemple', " parmi d'autres", ' peut encore servir']

join(liste) : rassemble une liste de chaînes en une seule (Cette méthode fait donc l'inverse de la précédente). Attention : la chaîne à laquelle on applique cette méthode est celle qui servira de séparateur (un ou plusieurs caractères) ; l'argument transmis est la liste des chaînes à rassembler.

>>> tableau = ["Salut", "les", "copains"]
>>> print  " ".join(tableau)
Salut les copains
>>> print  "___".join(tableau)
Salut___les___copains

pop(i) retire et renvoie l'élément de la liste d'index i. Si i est vide, il traite le dernier élément.

>>> list = [1, 2, 3, 4]

>>> print(list.pop(0))
1
>>> list
[2, 3, 4]

>>> print(list.pop())
4
>>>list
[2, 3]


La fonction intégrée len(), que nous avons déjà rencontrée à propos des chaînes, s'applique aussi aux listes. Elle renvoie le nombre d'éléments présents dans la liste :

>>> len(jour)
7

Supposons par exemple que vous voulez créer une liste B qui contienne le même nombre d'éléments qu'une autre liste A. Vous pouvez obtenir ce résultat de différentes manières, mais l'une des plus simples consistera à effectuer : B = [0]*len(A).

Une autre fonction intégrée permet de supprimer d'une liste un élément ou plusieurs éléments quelconques à partir de leurs index. Il s'agit de la fonction del() :

>>> jour = ['lundi', 'mardi', 'mercredi', 'jeudi', 'vendredi', 476, 3.142]

>>> del(jour[5:7])
>>> print(jour)
['lundi', 'mardi', 'mercredi', 'jeudi', 'vendredi']

>>> del(jour[0])
>>> print(jour)
['mardi', 'mercredi', 'jeudi', 'vendredi']
 notez bien la différence entre la méthode remove() et la fonction del() : del travaille avec un indice ou une tranche d'indices, tandis que remove() recherche une valeur (si plusieurs éléments de la liste possèdent la même valeur, seul le premier est effacé).
  • min(liste) : minimum d'une liste (élément ayant la plus petite valeur).
  • max(liste) : maximum d'une liste.
>>> jour = ['lundi', 'mardi', 'mercredi', 'jeudi', 'vendredi']

>>> min(jour)
'jeudi'

>>> max(jour)
'vendredi'

Si vous devez manipuler des séquences de nombres, vous pouvez les créer très aisément à l'aide de cette fonction :

>>> range(10)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

Sous python 3.6: print(list(range(10))) La fonction range() génère une liste de nombres entiers de valeurs croissantes. Si vous appelez range() avec un seul argument, la liste contiendra un nombre de valeurs égal à l'argument fourni, mais en commençant à partir de zéro (c'est-à-dire que range(n) génère les nombres de 0 à n-1).

Notez bien que l'argument fourni n'est jamais dans la liste générée.

On peut aussi utiliser range() avec deux, ou même trois arguments séparés par des virgules, afin de générer des séquences de nombres plus spécifiques :

>>> range(5,13)
[5, 6, 7, 8, 9, 10, 11, 12]
>>> range(3,16,3)
[3, 6, 9, 12, 15]

Si vous avez du mal à assimiler l'exemple ci-dessus, considérez que range() attend toujours trois arguments, que l'on pourrait intituler FROM, TO et STEP. FROM est la première valeur à générer, TO est la dernière (ou plutôt la dernière + un), et STEP le « pas » à sauter pour passer d'une valeur à la suivante. S'ils ne sont pas fournis, les paramètres FROM et STEP prennent leurs valeurs par défaut, qui sont respectivement 0 et 1.

Parcours d'une liste à l'aide de for, range() et len()

[modifier | modifier le wikicode]

L'instruction for est l'instruction idéale pour parcourir une liste :

>>> prov = ['La','raison','du','plus','fort','est','toujours','la','meilleure']
>>> for mot in prov:
       print mot,
La raison du plus fort est toujours la meilleure

Il est très pratique de combiner les fonctions range() et len() pour obtenir automatiquement tous les indices d'une séquence (liste ou chaîne). Exemple :

fable = ['Maître','Corbeau','sur','un','arbre','perché']
for index in range(len(fable)):
    print index, fable[index]

Mais il existe également une syntaxe adaptée à cela :

for (cle, valeur) in enumerate(fable):
    print(cle, valeur)

L'exécution de ce script donne le résultat :

0 Maître
1 Corbeau
2 sur
3 un
4 arbre
5 perché

Tableau à trois lignes :

monTableau = range(1, 5)
monTableau[1] = u'ligne 1'
monTableau[2] = u'ligne 2'
monTableau[3] = u'ligne 3'

for ligne in range(1, 4):
    print(monTableau[ligne])

Tableau à deux dimensions :

ligne = 3
colonne = 2
monTableau = [[0] * (colonne+1) for _ in range(ligne+1)]
monTableau[1][1] = u'1.1'
monTableau[1][2] = u'1.2'
monTableau[2][1] = u'2.1'
monTableau[2][2] = u'2.2'
monTableau[3][1] = u'3.1'
monTableau[3][2] = u'3.2'

for l in range(1, ligne + 1):
    for c in range(1, colonne + 1):
        print(monTableau[l][c])

Une conséquence du typage dynamique

[modifier | modifier le wikicode]

Le type de la variable utilisée avec l'instruction "for" est redéfini continuellement au fur et à mesure du parcours : même si les éléments d'une liste sont de types différents, on peut parcourir cette liste à l'aide de "for" sans qu'il ne s'ensuive une erreur, car le type de la variable de parcours s'adapte automatiquement à celui de l'élément en cours de lecture. Exemple :

>>> divers = [3, 17.25, [5, 'Jean'], 'Linux is not Windoze']
>>> for item in divers:
        print item, type(item)
3 <type 'int'>
17.25 <type 'float'>
[5, 'Jean'] <type 'list'>
Linux is not Windoze <type 'str'>

La plupart des programmes d'ordinateur font exactement la même chose chaque fois qu'on les exécute. De tels programmes sont dits déterministes. Le déterminisme est certainement une bonne chose : nous voulons évidemment qu'une même série de calculs appliquée aux mêmes données initiales aboutisse toujours au même résultat. Pour certaines applications, cependant, nous pouvons souhaiter que l'ordinateur soit imprévisible. Le cas des jeux constitue un exemple évident, mais il en existe bien d'autres.

Contrairement aux apparences, il n'est pas facile du tout d'écrire un algorithme qui soit réellement non-déterministe (c'est-à-dire qui produise un résultat totalement imprévisible). Il existe cependant des techniques mathématiques permettant de simuler plus ou moins bien l'effet du hasard. Des livres entiers ont été écrits sur les moyens de produire ainsi un hasard « de bonne qualité ». Nous n'allons évidemment pas développer ici une telle question, mais rien ne vous empêche de consulter à ce sujet votre professeur de mathématiques.

Dans son module random, Python propose toute une série de fonctions permettant de générer des nombres aléatoires qui suivent différentes distributions mathématiques. Nous n'examinerons ici que quelques-unes d'entre elles. Veuillez consulter la documentation en ligne pour découvrir les autres. Vous pouvez importer toutes les fonctions du module par :

>>> from random import *

Pour créer une liste de nombres réels aléatoires, de valeur comprise entre zéro et un :

>>> s = [0]*tailleListe
    for i in range(tailleListe):
        s[i] = random()
    print(s)

Vous pouvez constater que nous avons pris le parti de construire d'abord une liste de zéros de taille n, et ensuite de remplacer les zéros par des nombres aléatoires.

Exercices

  1. Réécrivez la fonction list_aleat() ci-dessus, en utilisant la méthode append() pour construire la liste petit à petit à partir d'une liste vide (au lieu de remplacer les zéros d'une liste préexistante comme nous l'avons fait).
  2. Écrivez une fonction imprime_liste() qui permette d'afficher ligne par ligne tous les éléments contenus dans une liste de taille quelconque. Le nom de la liste sera fourni en argument. Utilisez cette fonction pour imprimer la liste de nombres aléatoires générés par la fonction list_aleat(). Ainsi par exemple, l'instruction imprime_liste(liste_aleat(8)) devra afficher une colonne de 8 nombres réels aléatoires.

Solution

  1. Réfléchissez !
  2. Réfléchissez !

Les nombres ainsi générés sont-ils vraiment aléatoires ? C'est difficile à dire. Si nous ne tirons qu'un petit nombre de valeurs, nous ne pouvons rien vérifier. Par contre, si nous utilisons un grand nombre de fois la fonction random(), nous nous attendons à ce que la moitié des valeurs produites soient plus grandes que 0,5 (et l'autre moitié plus petites).

Affinons ce raisonnement. Les valeurs tirées sont toujours dans l'intervalle 0-1. Partageons cet intervalle en 4 fractions égales : de 0 à 0,25 , de 0,25 à 0,5 , de 0,5 à 0,75 , et de 0,75 à 1. Si nous tirons un grand nombre de valeurs au hasard, nous nous attendons à ce qu'il y en ait autant qui se situent dans chacune de nos 4 fractions. Et nous pouvons généraliser ce raisonnement à un nombre quelconque de fractions, du moment qu'elles soient égales.

Exercices

  1. Vous allez écrire un programme destiné à vérifier le fonctionnement du générateur de nombres aléatoires de Python en appliquant la théorie exposée ci-dessus. Votre programme devra donc : a) Demander à l'utilisateur le nombre de valeurs à tirer au hasard à l'aide de la fonction random(). Il serait intéressant que le programme propose un nombre par défaut (1000 par exemple). b) Demander à l'utilisateur en combien de fractions il souhaite partager l'intervalle des valeurs possibles (c'est-à-dire l'intervalle de 0 à 1). Ici aussi, il faudrait proposer un nombre de par défaut (5 fractions, par exemple). Vous pouvez également limiter le choix de l'utilisateur à un nombre compris entre 2 et le 1/10e du nombre de valeurs tirées au hasard. c) Construire une liste de N compteurs (N étant le nombre de fractions souhaitées). Chacun d'eux sera évidemment initialisé à zéro. d) Tirer au hasard toutes les valeurs demandées, à l'aide de la fonction random(), et mémoriser ces valeurs dans une liste. e) Mettre en œuvre un parcours de la liste des valeurs tirées au hasard (boucle), et effectuer un test sur chacune d'elles pour déterminer dans quelle fraction de l'intervalle 0-1 elle se situe. Incrémenter de une unité le compteur correspondant. f) Lorsque c'est terminé, afficher l'état de chacun des compteurs.

Solution

  1. # Test du générateur de nombres aléatoires :
    from random import random           # tire au hasard un réel entre 0 et 1
    
    n = raw_input("Nombre de valeurs à tirer au hasard (défaut = 1000) : ")
    if n == "":
        nVal =1000
    else:
        nVal = int(n)
    
    n = raw_input("Nombre de fractions dans l'intervalle 0-1 (entre 2 et "
                  + str(nVal/10) + ", défaut =5) : ")
    if n == "":
        nFra =5
    else:
        nFra = int(n)
    
    if nFra < 2:
        nFra =2
    elif nFra > nVal/10:
        nFra = nVal/10
    
    print "Tirage au sort des", nVal, "valeurs ..."
    listVal = [0]*nVal                      # créer une liste de zéros
    for i in range(nVal):                   # puis modifier chaque élément
        listVal[i] = random()
    
    print "Comptage des valeurs dans chacune des", nFra, "fractions ..."
    listCompt = [0]*nFra                    # créer une liste de compteurs
    
    # parcourir la liste des valeurs :
    for valeur in listVal:
        # trouver l'index de la fraction qui contient la valeur :    
        index = int(valeur*nFra)
        # incrémenter le compteur correspondant :
        listCompt[index] = listCompt[index] +1
    
    # afficher l'état des compteurs :
    for compt in listCompt:
        print compt,
    

Exemple de résultats affichés par un programme de ce type

[modifier | modifier le wikicode]
Nombre de valeurs à tirer au hasard (défaut = 1000) : 100
Nombre de fractions dans l'intervalle 0-1 (entre 2 et 10, défaut =5) : 5
Tirage au sort des 100 valeurs ...
Comptage des valeurs dans chacune des 5 fractions ...
11 30 25 14 20 
Nombre de valeurs à tirer au hasard (défaut = 1000) : 10000
Nombre de fractions dans l'intervalle 0-1 (entre 2 et 1000, défaut =5) : 5
Tirage au sort des 10000 valeurs ...
Comptage des valeurs dans chacune des 5 fractions ...
1970 1972 2061 1935 2062

Une bonne approche de ce genre de problème consiste à essayer d'imaginer quelles fonctions simples vous pourriez écrire pour résoudre l'une ou l'autre partie du problème, puis de les utiliser dans un ensemble plus vaste.

Par exemple, vous pourriez chercher à définir d'abord une fonction numeroFraction() qui servirait à déterminer dans quelle fraction de l'intervalle 0-1 une valeur tirée se situe. Cette fonction attendrait deux arguments (la valeur tirée, le nombre de fractions choisi par l'utilisateur) et fournirait en retour l'index du compteur à incrémenter (c'est-à-dire le n° de la fraction correspondante). Il existe peut-être un raisonnement mathématique simple qui permette de déterminer l'index de la fraction à partir de ces deux arguments. Pensez notamment à la fonction intégrée int(), qui permet de convertir un nombre réel en nombre entier en éliminant sa partie décimale.

Si vous ne trouvez pas, une autre réflexion intéressante serait peut-être de construire d'abord une liste contenant les valeurs « pivots » qui délimitent les fractions retenues (par exemple 0 – 0,25 – 0,5 – 0,75 - 1 dans le cas de 4 fractions). La connaissance de ces valeurs faciliterait peut-être l'écriture de la fonction numeroFraction() que nous souhaitons mettre au point.

Si vous disposez d'un temps suffisant, vous pouvez aussi réaliser une version graphique de ce programme, qui présentera les résultats sous la forme d'un histogramme (diagramme « en bâtons »).

Tirage au hasard de nombres entiers

[modifier | modifier le wikicode]

Lorsque vous développerez des projets personnels, il vous arrivera fréquemment de souhaiter pouvoir disposer d'une fonction qui permette de tirer au hasard un nombre entier entre certaines limites. Par exemple, si vous voulez écrire un programme de jeu dans lequel des cartes à jouer sont tirées au hasard (à partir d'un jeu ordinaire de 52 cartes), vous aurez certainement l'utilité d'une fonction capable de tirer au hasard un nombre entier compris entre 1 et 52.

Vous pouvez pour ce faire utiliser la fonction randrange() du module random.

Cette fonction peut être utilisée avec 1, 2 ou 3 arguments.

Avec un seul argument, elle renvoie un entier compris entre zéro et la valeur de l'argument diminué d'une unité. Par exemple, randrange(6) renvoie un nombre compris entre 0 et 5.

Avec deux arguments, le nombre renvoyé est compris entre la valeur du premier argument et la valeur du second argument diminué d'une unité. Par exemple, randrange(2, 8) renvoie un nombre compris entre 2 et 7.

Si l'on ajoute un troisième argument, celui-ci indique que le nombre tiré au hasard doit faire partie d'une série limitée d'entiers, séparés les uns des autres par un certain intervalle, défini lui-même par ce troisième argument. Par exemple, randrange(3, 13, 3) renverra un des nombres de la série 3, 6, 9, 12 :

>>> for i in range(15):
        print random.randrange(3,13,3),

3 12 6 9 6 6 12 6 3 6 9 3 6 12 12

Exercices

  1. Écrivez un script qui tire au hasard des cartes à jouer. Le nom de la carte tirée doit être correctement présenté, « en clair ». Le programme affichera par exemple : Frappez <Enter> pour tirer une carte :
    Dix de Trèfle
    Frappez <Enter> pour tirer une carte :
    As de Carreau
    Frappez <Enter> pour tirer une carte :
    Huit de Pique
    Frappez <Enter> pour tirer une carte :
    etc ...

Solution

  1. # Tirage de cartes
    from random import randrange
    
    couleurs = ['Pique', 'Trèfle', 'Carreau', 'Cœur']
    valeurs = [2, 3, 4, 5, 6, 7, 8, 9, 10, 'valet', 'dame', 'roi', 'as']
    
    # Construction de la liste des 52 cartes :
    carte =[]
    for coul in couleurs:
         for val in valeurs:
              carte.append("%s de %s" % (str(val), coul))
    
    # Tirage au hasard :
    while 1:
         k = raw_input("Frappez <c> pour tirer une carte, <Enter> pour terminer ") 
         if k =="":
              break
         r = randrange(52)
         print carte[r]
    

Permet d'appliquer une fonction à toutes les entrées d'une liste. Par exemple pour les trimer :

l = [' ma super ligne 1\n', ' ma super ligne 2\n']
l = map(str.strip, l)
print l
# ['ma super ligne 1', 'ma super ligne 2']

Exercices

  1. Soient les listes suivantes : t1 = [31,28,31,30,31,30,31,31,30,31,30,31]
    t2 = ['Janvier','Février','Mars','Avril','Mai','Juin',
    'Juillet','Août','Septembre','Octobre','Novembre','Décembre'] Écrivez un petit programme qui insère dans la seconde liste tous les éléments de la première, de telle sorte que chaque nom de mois soit suivi du nombre de jours correspondant : ['Janvier',31,'Février',28,'Mars',31, etc.].
  2. Créez une liste A contenant quelques éléments. Effectuez une vraie copie de cette liste dans une nouvelle variable B. Suggestion : créez d'abord une liste B de même taille que A mais ne contenant que des zéros. Remplacez ensuite tous ces zéros par les éléments tirés de A.
  3. Même question, mais autre suggestion : créez d'abord une liste B vide. Remplissez-la ensuite à l'aide des éléments de A ajoutés l'un après l'autre.
  4. Même question, autre suggestion encore : pour créer la liste B, découpez dans la liste A une tranche incluant tous les éléments (à l'aide de l'opérateur [:]).
  5. Un nombre premier est un nombre qui n'est divisible que par un et par lui-même. Écrivez un programme qui établisse la liste de tous les nombres premiers compris entre 1 et 1000, en utilisant la méthode du crible d'Ératosthène :
    • Créez une liste de 1000 éléments, chacun initialisé à la valeur 1.
    • Parcourez cette liste à partir de l'élément d'indice 2 : si l'élément analysé possède la valeur 1, mettez à zéro tous les autres éléments de la liste, dont les indices sont des multiples entiers de l'indice auquel vous êtes arrivé.
    Lorsque vous aurez parcouru ainsi toute la liste, les indices des éléments qui seront restés à 1 seront les nombres premiers recherchés. En effet, à partir de l'indice 2, vous annulez tous les éléments d'indices pairs : 4, 6, 8, 10, etc. Avec l'indice 3, vous annulez les éléments d'indices 6, 9, 12, 15, etc., et ainsi de suite. Seuls resteront à 1 les éléments dont les indices sont effectivement des nombres premiers.

Solution

  1. # Insertion de nouveaux éléments dans une liste existante
    
    t1 = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
    t2 = ['Janvier','Février','Mars','Avril','Mai','Juin',
          'Juillet','Août','Septembre','Octobre','Novembre','Décembre']
    
    c, d = 1, 0
    while d < 12 :
         t2[c:c] = [t1[d]]       # ! l'élément inséré doit être une liste
         c, d = c+2, d+1
    </pre>
    </li>
    
    <li>Réfléchissez !</li>
    
    <li>Réfléchissez !</li>
    
    <li>Réfléchissez !</li>
    
    <li>
    <syntaxhighlight lang=python>
    # Crible d’Ératosthène pour rechercher les nombres premiers de 1 à 999
    
    # Créer une liste de 1000 éléments 1 (leurs indices vont de 0 à 999) :
    lst = [1]*1000           
    # Parcourir la liste à partir de l'élément d'indice 2:
    for i in range(2,1000):
        # Mettre à zéro les éléments suivants dans la liste,
        # dont les indices sont des multiples de i :
        for j in range(i*2, 1000, i):
            lst[j] = 0
    
    # Afficher les indices des éléments restés à 1 (on ignore l'élément 0) :
    for i in range(1,1000):
        if lst[i]:
            print i,
    

Exercices

  1. Déterminez vous-même ce qui se passe lorsque l'un ou l'autre des indices de découpage est erroné, et décrivez cela le mieux possible (si le second indice est plus petit que le premier, par exemple, ou bien si le second indice est plus grand que la taille de la chaîne).
  2. Découpez une grande chaîne en fragments de cinq caractères chacun. Rassemblez ces morceaux dans l'ordre inverse.
  3. Tâchez d'écrire un script qui fera exactement le contraire de ce que fait l'opérateur d'indexage ([]) : au lieu de partir d'un index donné pour retrouver le caractère correspondant, il devra retrouver l'index correspondant à un caractère donné, à partir du nom de la chaîne à traiter et du caractère à trouver. Exemple : pour "Juliette & Roméo", "&" il devra afficher : 9, ou -1 si le caractère est introuvable.
  4. Améliorez le script en lui ajoutant une troisième variable : l'index à partir duquel la recherche doit s'effectuer dans la chaîne. Ainsi par exemple, pour : "César & Cléopâtre", "r", 5, il devra afficher : 15 (et non 4 !)
  5. Écrivez un script qui compte le nombre d'occurrences d'un caractère donné dans une chaîne. Ainsi, pour "ananas au jus", "a" il devra afficher : 4.

Solution

  1. IndexError: list index out of range
  2. # Découpage d'une chaîne en fragments :
    chain ="abcdefghijklmnopqrstuvwxyz123456789"
    n = 5
    
    # Découpage de "chain" en une liste de fragments de n caractères"
    d, f = 0, n             # indices de début et de fin de fragment
    tt = []                 # liste à construire
    while d < len(chain):
    	if f > len(chain):  # on ne peut pas découper au-delà de la fin
    		f = len(chain)
    	fr = chain[d:f]     # découpage d'un fragment
    	tt.append(fr)       # ajout du fragment à la liste
    	d, f = f, f + n      # indices suivants 
    print(tt)
    
    # Rassemble les éléments de la liste tt dans l'ordre inverse"
    chain = ""              # chaîne à construire
    i = len(tt)             # on commence par la fin de la liste
    while i > 0 :
    	i = i - 1           # le dernier élément possède l'indice n - 1
    	chain = chain + tt[i]
    print(chain)
    
  3. # Rechercher l'indice d'un caractère dans une chaîne
    chain, car = "Coucou c'est moi", "z"
    start = 0
    
    # Trouve l'indice du caractère car dans "chain"
    i = start
    while i < len(chain):
    	if chain[i] == car:
    		print(i)	# le caractère est trouvé -> on termine
    	i = i + 1
    print(-1)       		# toute la chaîne a été scannée sans succès 
    
    # Autres tests :
    chain, car = "Juliette & Roméo", "&"
    chain, car, start = "César & Cléopâtre", "r", 5
    
  4. Réfléchissez !
  5. Réfléchissez !

Exercices

  1. Soient les listes suivantes :
    t1 = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
    t2 = ['Janvier', 'Février', 'Mars', 'Avril', 'Mai', 'Juin',
          'Juillet', 'Août', 'Septembre', 'Octobre', 'Novembre', 'Décembre']
    
    Écrivez un petit programme qui crée une nouvelle liste t3. Celle-ci devra contenir tous les éléments des deux listes en les alternant, de telle manière que chaque nom de mois soit suivi du nombre de jours correspondant : ['Janvier',31,'Février',28,'Mars',31, etc.].
  2. Écrivez un programme qui affiche « proprement » tous les éléments d'une liste. Si on l'appliquait par exemple à la liste t2 de l'exercice ci-dessus, on devrait obtenir :
    Janvier Février Mars Avril Mai Juin Juillet Août Septembre Octobre Novembre Décembre
    
  3. Écrivez un programme qui recherche le plus grand élément présent dans une liste donnée. Par exemple, si on l'appliquait à la liste [32, 5, 12, 8, 3, 75, 2, 15], ce programme devrait afficher :
    le plus grand élément de cette liste a la valeur 75.
    
  4. Écrivez un programme qui analyse un par un tous les éléments d'une liste de nombres (par exemple celle de l'exercice précédent) pour générer deux nouvelles listes. L'une contiendra seulement les nombres pairs de la liste initiale, et l'autre les nombres impairs. Par exemple, si la liste initiale est celle de l'exercice précédent, le programme devra construire une liste pairs qui contiendra [32, 12, 8, 2], et une liste impairs qui contiendra [5, 3, 75, 15]. Astuce : pensez à utiliser l'opérateur modulo (%) déjà cité précédemment.
  5. Écrivez un programme qui analyse un par un tous les éléments d'une liste de mots (par exemple : ['Jean', 'Maximilien', 'Brigitte', 'Sonia', 'Jean-Pierre', 'Sandra'] pour générer deux nouvelles listes. L'une contiendra les mots comportant moins de 6 caractères, l'autre les mots comportant 6 caractères ou davantage.

Solution

  1. # Combinaison de deux listes en une seule
    
    # Listes fournies au départ :
    t1 = [31,28,31,30,31,30,31,31,30,31,30,31]
    t2 = ['Janvier','Février','Mars','Avril','Mai','Juin',
          'Juillet','Août','Septembre','Octobre','Novembre','Décembre']
    # Nouvelle liste à construire (vide au départ) :
    t3 = []
    # Boucle de traitement :
    i = 0
    while i < len(t1):
        t3.append(t2[i])
        t3.append(t1[i])
        i = i + 1
    
    # Affichage :
    print t3
    
  2. # Affichage des éléments d'une liste
    
    # Liste fournie au départ :
    t2 = ['Janvier','Février','Mars','Avril','Mai','Juin',
          'Juillet','Août','Septembre','Octobre','Novembre','Décembre']
    # Affichage :
    i = 0
    while i < len(t2):
        print t2[i],
        i = i + 1
    
  3. # Recherche du plus grand élément d'une liste
    
    # Liste fournie au départ :
    tt = [32, 5, 12, 8, 3, 75, 2, 15]
    # Au fur et à mesure du traitement de la liste, on mémorisera dans
    # la variable ci-dessous la valeur du plus grand élément déjà trouvé :
    max = 0
    # Examen de tous les éléments :
    i = 0
    while i < len(tt):
        if tt[i] > max:
            max = tt[i]         # mémorisation d'un nouveau maximum
        i = i + 1
    # Affichage :
    print "Le plus grand élément de cette liste a la valeur", max
    
  4. # Séparation des nombres pairs et impairs
    
    # Liste fournie au départ :
    tt = [32, 5, 12, 8, 3, 75, 2, 15]
    pairs = []
    impairs = []
    # Examen de tous les éléments :
    i = 0
    while i < len(tt):
        if tt[i] % 2 == 0:
            pairs.append(tt[i])
        else:
            impairs.append(tt[i])
        i = i + 1
    # Affichage :
    print "Nombres pairs :", pairs
    print "Nombres impairs :", impairs
    
  5. Réfléchissez !

Exercices

  1. Écrivez un script qui génère la liste des carrés et des cubes des nombres de 20 à 40.
  2. Écrivez un script qui crée automatiquement la liste des sinus des angles de 0° à 90° , par pas de 5°. Attention : la fonction sin() du module math considère que les angles sont fournis en radians (360° = 2 p radians)
  3. Écrivez un script qui permette d'obtenir à l'écran les 15 premiers termes des tables de multiplication par 2, 3, 5, 7, 11, 13, 17, 19 (ces nombres seront placés au départ dans une liste) sous la forme d'une table semblable à la suivante :
    2 4 6 8 10 12 14 16 18 20 22 24 26 28 30
    3 6 9 12 15 18 21 24 27 30 33 36 39 42 45
    5 10 15 20 25 30 35 40 45 50 55 60 65 70 75
    etc.
  4. Soit la liste suivante :
    ['Jean-Michel', 'Marc', 'Vanessa', 'Anne', 'Maximilien', 'Alexandre-Benoît', 'Louise']
    Écrivez un script qui affiche chacun de ces noms avec le nombre de caractères correspondant.
  5. Vous disposez d'une liste de nombres entiers quelconques, certains d'entre eux étant présents en plusieurs exemplaires. Écrivez un script qui recopie cette liste dans une autre, en omettant les doublons. La liste finale devra être triée.
  6. Écrivez un script qui recherche le mot le plus long dans une phrase donnée (l'utilisateur du programme doit pouvoir entrer une phrase de son choix).
  7. Écrivez un script capable d'afficher la liste de tous les jours d'une année imaginaire, laquelle commencerait un Jeudi. Votre script utilisera lui-même trois listes : une liste des noms de jours de la semaine, une liste des noms des mois, et une liste des nombres de jours que comportent chacun des mois (ne pas tenir compte des années bissextiles).
    Exemple de sortie :
    Jeudi 1 Janvier Vendredi 2 Janvier Samedi 3 Janvier Dimanche 4 Janvier
    ... et ainsi de suite jusqu'au Jeudi 31 Décembre.
  8. Vous avez à votre disposition un fichier texte qui contient un certain nombre de noms d'élèves. Écrivez un script qui effectue une copie triée de ce fichier.
  9. Écrivez un script permettant de trier une liste. Il ne pourra pas utiliser la méthode intégrée "sort()" de Python : vous devez donc définir vous-même l'algorithme de tri.

Solution

  1. Réfléchissez !
  2. Réfléchissez !
  3. # Affichage de tables de multiplication
    m, n = 3, 15
    chain =""
    for i in range(n):
        v = m * (i+1)               # calcul d'un des termes
        chain = chain + "%4d" % (v) # formatage à 4 caractères
    print(chain)
    
    3   6   9  12  15  18  21  24  27  30  33  36  39  42  45
    
  4. # Simple parcours d'une liste :
    lst = ['Jean-Michel', 'Marc', 'Vanessa', 'Anne',
           'Maximilien', 'Alexandre-Benoît', 'Louise']
    
    for e in lst:
        print("%s : %s caractères" % (e, len(e)))
    
  5. # Élimination de doublons
    
    lst = [9, 12, 40, 5, 12, 3, 27, 5, 9, 3, 8, 22, 40, 3, 2, 4, 6, 25]
    lst2 = []
    
    for el in lst:
        if el not in lst2:
            lst2.append(el)
    
    lst2.sort()
    print(lst2)
    
  6. Réfléchissez !
  7. # Afficher tous les jours d'une année :
    ## Cette variante utilise une liste de listes ##
    ## (que l'on pourrait aisément remplacer par deux listes distinctes)
    
    # La liste ci-dessous contient deux éléments qui sont eux-mêmes des listes.
    # l'élément 0 contient les nombres de jours de chaque mois, tandis que
    # l'élément 1 contient les noms des douze mois :
    mois = [[31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31],
            ['Janvier', 'Février', 'Mars', 'Avril', 'Mai', 'Juin', 'Juillet',
             'Août', 'Septembre', 'Octobre', 'Novembre', 'Décembre']]
    
    jour = ['Dimanche','Lundi','Mardi','Mercredi','Jeudi','Vendredi','Samedi']
    
    ja, jm, js, m = 0, 0, 0, 0
    
    while ja <365:
        ja, jm = ja +1, jm +1    # ja = jour dans l'année, jm = jour dans le mois
        js = (ja +3) % 7         # js = jour de la semaine. Le décalage ajouté 
                                 #      permet de choisir le jour de départ
      
        if jm > mois[0][m]:               # élément m de l'élément 0 de la liste
            jm, m = 1, m+1
    
        print jour[js], jm, mois[1][m]    # élément m de l'élément 1 de la liste
    
  8. Réfléchissez !
  9. Réfléchissez !