Aller au contenu

🏁 Les listes en compréhension⚓︎

Sans condition⚓︎

Créer une liste contenant de nombreux éléments peut se faire à l'aide d'une boucle « Pour ». Le script ci-dessous crée par exemple la liste des éléments entre 0 et 100 :

🐍 Script Python
entiers = []
for x in range(101):
    entiers.append(x)

Python propose une autre façon de créer la même liste : la liste en compréhension.

Le schéma général est [valeur for element in iterable] dans lequel :

  • valeur est une valeur quelconque. Cela peut être un entier, une chaîne de caractère, obtenu en effectuant un calcul à l'aide de element ou sans rapport avec ce dernier...,

  • element prend les différentes valeurs présentes dans iterable,

  • iterable est un objet que Python peut parcourir. Ce peut être une liste, un tuple, un dictionnaire, un objet de type range...

Par exemple :

  • Les entiers entre 0 et 4 :

    🐍 Console Python
    >>> [x for x in range(5)]
    [0, 1, 2, 3, 4]
    
  • Les entiers pairs entre 0 et 8 :

    🐍 Console Python
    >>> [2 * x for x in range(5)]
    [0, 2, 4, 6, 8]
    
  • La liste des lettres de "python" :

    🐍 Console Python
    >>> [lettre for lettre in "python"]
    ['p', 'y', 't', 'h', 'o', 'n']
    
  • La liste des lettres de "python" en majuscule :

    🐍 Console Python
    >>> [lettre.upper() for lettre in "python"]
    ['P', 'Y', 'T', 'H', 'O', 'N']
    
Comment faire ?

On souhaite obtenir la liste des entiers entre 3 (inclus) et 103 (inclus).

Quelles instructions renvoient cette liste ?

  • [k in range(3, 104)]
  • [k for k in range(3, 103)]
  • [k for k in range(3, 104)]
  • [k + 3 for k in range(101)]
  • [k // 2 for k in range(6, 208)]
  • ❌ [k in range(3, 104)] est syntaxiquement incorrect, la structure attendue est [valeur for element in iterable]
  • ❌ [k for k in range(3, 103)] génère [3, 4, ..., 102]. Il manque la dernière valeur
  • ✅ [k for k in range(3, 104)]
  • ✅ [k + 3 for k in range(101)]
  • ❌ [k // 2 for k in range(6, 208)] pourrait fonctionner si l'on utilisait un pas égal à 2. Ici on génère la liste [3, 3, 4, 4, ..., 103, 103]
Dans un terminal

Utilisez le terminal ci-dessous afin de créer les listes suivantes :

  1. les entiers entre 0 et 10 (inclus l'un et l'autre)
  2. les entiers entre -10 et 10 (inclus l'un et l'autre)
  3. les entiers pairs entre -10 et 10 (inclus l'un et l'autre)
  4. les multiples de 3 entre -30 et 30 (inclus l'un et l'autre)
  5. vingt fois la valeur None
  6. la liste des caractères de "Hello World"
  7. la liste des caractères de "Hello World" en minuscule (Python considère que la minuscule de ' ' est ' ' !)
Astuce : mettre en minuscule
🐍 Console Python
>>> "A".lower()
'a'
>>> " ".lower()
' '

Solution
  1. [k for k in range(0, 11)]
  2. [k for k in range(-10, 11)]
  3. [k for k in range(-10, 11, 2)]
  4. [k for k in range(-30, 31, 3)]
  5. [None for _ in range(20)]. La variable d'itération n'étant pas utilisée, on peut la nommer _
  6. [caractere for caractere in "Hello World"]
  7. [caractere.lower() for caractere in "Hello World"]
Générer l'alphabet

On cherche dans cet exercice à créer la liste de toutes les lettres de l'alphabet en majuscule. Plusieurs options s'offrent à nous :

  • écrire la liste à la main. C'est fastidieux et nous ne sommes pas à l'abri d'un oubli ou d'une erreur...
  • s'appuyer sur la table ASCII qui contient déjà tous ces caractères.

On en fournit ci-dessous un extrait :

... "A" "B" "C" ... "Y" "Z" "[" ...

Comme on peut le voir, les caractères de l'alphabet en majuscule sont tous à la suite dans la table. Chacun est associé à un code (non donné dans le tableau). Ces codes sont des entiers consécutifs (le code de "B" est égal à celui de "A" augmenté de 1...).

La fonction ord de Python permet d'obtenir le code d'un caractère présent dans la table ASCII. Par exemple ord("@") renvoie 64.

La fonction chr fait l'opération réciproque : elle prend en argument un entier et renvoie le caractère correspondant de la table ASCII. Ainsi : chr(64) renvoie '@'.

Utilisez le terminal ci-dessous afin de créer la liste contenant toutes les lettres de l'alphabet en majuscule.

On rajoute les contraintes suivantes :

  • il est interdit d'écrire directement l'alphabet : vous devez utiliser une liste en compréhension ;

  • afin de corser la difficulté, on interdit de plus d'utiliser des chiffres autres que le 1 ! Il est donc interdit de saisir « en dur » le code du "A" et celui du "Z". Rien n'empêche par contre d'utiliser ord("A")...

Solution

On peut faire [chr(k) for k in range(ord("A"), ord("Z") + 1)]. On est ainsi sûr de n'oublier aucune lettre !

Sans la contrainte sur les caractères numériques, on peut faire [chr(k) for k in range(ord("A"), ord("A") + 26)]

Avec condition⚓︎

Les listes en compréhension sont encore plus intéressantes lorsque l'on rajoute des conditions. La structure générale devient alors [valeur for element in iterable if condition] :

  • valeur, element et iterable répondent aux même spécifications que dans la version de base,
  • condition est une expression renvoyant un booléen (True ou False).

Par exemple :

  • Les entiers pairs entre 0 et 10 :

    🐍 Console Python
    >>> [x for x in range(11) if x % 2 == 0]
    [0, 2, 4, 6, 8, 10]
    
  • Les notes comprises entre 12 et 14 (inclus l'un et l'autre):

    🐍 Console Python
    >>> notes = [17, 11, 13, 14, 10, 19, 13]
    >>> [x for x in notes if 12 <= x <= 14]
    [13, 14, 13]
    
  • Les fleurs débutants par le caractère "A" :

    🐍 Console Python
    >>> fleurs = ("Arum", "Rose", "Azalée", "aster")
    >>> [f for f in fleurs if f[0] == "A"]
    ["Arum", "Azalée"]
    

    Remarque

    Notez que fleurs est un tuple mais que l'on crée bien une liste en compréhension.

Il est aussi possible d'utiliser des conditions complexes :

  • Les nombres pairs et inférieurs à 100 :

    🐍 Console Python
    >>> nombres = [353, 108, 98, 101, 79, 93]
    >>> [x for x in nombres if x % 2 == 0 and x <= 100]
    [98]
    
  • Les fleurs débutants par "A" ou dont le nom comporte moins de 4 caractères :

    🐍 Console Python
    >>> fleurs = ("Arum", "Rose", "Azalée", "aster")
    >>> [f for f in fleurs if f[0] == "A" or len(f) <= 4]
    ["Arum", "Rose", "Azalée"]
    
Qui fait quoi ?

On considère la liste nombres définie par nombres = [k for k in range(-10, 11)].

Cocher les informations correctes.

  • [x for x in nombres if x != 11] renvoie une copie de nombres
  • [x for x in nombres if x > 10] renvoie une liste vide
  • [True for x in nombres if x % 2 == 0] renvoie une liste d'autant de True que nombres compte de nombres pairs
  • [1 / x for x in nombres] renvoie la liste des inverses des valeurs de nombres
  • ✅ [x for x in nombres if x != 11] renvoie bien une copie de nombres
  • ✅ [x for x in nombres if x > 10] renvoie une liste vide car tous les éléments de nombres sont inférieurs ou égaux à 10
  • ✅ [True for x in nombres if x % 2 == 0] renvoie une liste autant de fois True que nombres compte de nombres pairs
  • ❌ [1 / x for x in nombres] renvoie une erreur car on demande à Python de diviser par 0
Filtrer des nombres aléatoires

Les instructions suivantes permettent de générer 1 000 nombres entiers aléatoires de -100 à 100 :

🐍 Script Python
from random import randrange
nombres = [randrange(-100, 101) for _ in range(1000)]

Compléter le code ci-dessous afin de filtrer cette liste comme demandée.

Au bout de 10 essais infructueux, le corrigé vous est proposé.

###
# Testsbksl-nl# listepy-und1 contient les valeurs strictement positives de nombresbksl-nlattendu = [x for x in nombres if x > 0]bksl-nlassert listepy-und1 == attendu, "Erreur sur la liste 1"bksl-nlbksl-nl# listepy-und2 contient les valeurs inférieures ou égales à 10 de nombresbksl-nlattendu = [x for x in nombres if x <= 10]bksl-nlassert listepy-und2 == attendu, "Erreur sur la liste 2"bksl-nlbksl-nl# listepy-und3 contient les valeurs impaires de nombresbksl-nlattendu = [x for x in nombres if x % 2 == 1]bksl-nlassert listepy-und3 == attendu, "Erreur sur la liste 3"bksl-nlbksl-nl# listepy-und4 contient les valeurs divisibles par 7 de nombresbksl-nlattendu = [x for x in nombres if x % 7 == 0]bksl-nlassert listepy-und4 == attendu, "Erreur sur la liste 4"bksl-nlbksl-nl# listepy-und5 contient les valeurs non divisibles par 5 de nombresbksl-nlattendu = [x for x in nombres if x % 5 != 0]bksl-nlassert listepy-und5 == attendu, "Erreur sur la liste 5"bksl-nlbksl-nl# listepy-und6 contient les valeurs dont le triple estbksl-nl# inférieur ou égal à 150 de nombresbksl-nlattendu = [x for x in nombres if 3 py-str x <= 150]bksl-nlassert listepy-und6 == attendu, "Erreur sur la liste 6"bksl-nlbksl-nl# listepy-und7 contient les valeurs paires et négatives de nombresbksl-nlattendu = [x for x in nombres if x % 2 == 0 and x <= 0]bksl-nlassert listepy-und7 == attendu, "Erreur sur la liste 7"bksl-nlbksl-nl# listepy-und8 contient les valeurs paires ou négatives de nombresbksl-nlattendu = [x for x in nombres if x % 2 == 0 or x <= 0]bksl-nlassert listepy-und8 == attendu, "Erreur sur la liste 8"bksl-nlbksl-nl# listepy-und9 contient les valeurs dont le chiffre des unités est 7bksl-nl# Conseil : Pensez à un modulo (x % ... == ...) de nombresbksl-nlattendu = [x for x in nombres if x % 10 == 7]bksl-nlassert listepy-und9 == attendu, "Erreur sur la liste 9"bksl-nlbksl-nl# listepy-und10 contient les valeurs comprises entre 0 (inclus) et 50 (inclus)bksl-nl# et dont le chiffre des unités est 3 de nombresbksl-nlattendu = [x for x in nombres if 0 <= x <= 50 and x % 10 == 3]bksl-nlassert listepy-und10 == attendu, "Erreur sur la liste 10"bksl-nlbksl-nl 10/10
from random import randrangebksl-nlnombres = [randrange(-100, 101) for py-und in range(1000)]bksl-nlbksl-nl# listepy-und1 contient les valeurs strictement positives de nombresbksl-nllistepy-und1 = ...bksl-nlbksl-nl# listepy-und2 contient les valeurs inférieures ou égales à 10 de nombresbksl-nllistepy-und2 = ...bksl-nlbksl-nl# listepy-und3 contient les valeurs impaires de nombresbksl-nllistepy-und3 = ...bksl-nlbksl-nl# listepy-und4 contient les valeurs divisibles par 7 de nombresbksl-nllistepy-und4 = ...bksl-nlbksl-nl# listepy-und5 contient les valeurs non divisibles par 5 de nombresbksl-nllistepy-und5 = ...bksl-nlbksl-nl# listepy-und6 contient les valeurs dont le triple estbksl-nl# inférieur ou égal à 150 de nombresbksl-nllistepy-und6 = ...bksl-nlbksl-nl# listepy-und7 contient les valeurs paires et négatives de nombresbksl-nllistepy-und7 = ...bksl-nlbksl-nl# listepy-und8 contient les valeurs paires ou négatives de nombresbksl-nllistepy-und8 = ...bksl-nlbksl-nl# listepy-und9 contient les valeurs dont le chiffre des unités est 7bksl-nl# Conseil : Pensez à un modulo (x % ... == ...) de nombresbksl-nllistepy-und9 = ...bksl-nlbksl-nl# listepy-und10 contient les valeurs comprises entre 0 (inclus) et 50 (inclus)bksl-nl# et dont le chiffre des unités est 3 de nombresbksl-nllistepy-und10 = ...bksl-nlbksl-nl# listepy-und1 contient les valeurs strictement positives de nombresbksl-nllistepy-und1 = [x for x in nombres if x > 0]bksl-nlbksl-nl# listepy-und2 contient les valeurs inférieures ou égales à 10 de nombresbksl-nllistepy-und2 = [x for x in nombres if x <= 10]bksl-nlbksl-nl# listepy-und3 contient les valeurs impaires de nombresbksl-nllistepy-und3 = [x for x in nombres if x % 2 == 1]bksl-nlbksl-nl# listepy-und4 contient les valeurs divisibles par 7 de nombresbksl-nllistepy-und4 = [x for x in nombres if x % 7 == 0]bksl-nlbksl-nl# listepy-und5 contient les valeurs non divisibles par 5 de nombresbksl-nllistepy-und5 = [x for x in nombres if x % 5 != 0]bksl-nlbksl-nl# listepy-und6 contient les valeurs dont le triple estbksl-nl# inférieur ou égal à 150 de nombresbksl-nllistepy-und6 = [x for x in nombres if 3 py-str x <= 150]bksl-nlbksl-nl# listepy-und7 contient les valeurs paires et négatives de nombresbksl-nllistepy-und7 = [x for x in nombres if x % 2 == 0 and x <= 0]bksl-nlbksl-nl# listepy-und8 contient les valeurs paires ou négatives de nombresbksl-nllistepy-und8 = [x for x in nombres if x % 2 == 0 or x <= 0]bksl-nlbksl-nl# listepy-und9 contient les valeurs dont le chiffre des unités est 7bksl-nl# Conseil : Pensez à un modulo (x % ... == ...) de nombresbksl-nllistepy-und9 = [x for x in nombres if x % 10 == 7]bksl-nlbksl-nl# listepy-und10 contient les valeurs comprises entre 0 (inclus) et 50 (inclus)bksl-nl# et dont le chiffre des unités est 3 de nombresbksl-nllistepy-und10 = [x for x in nombres if 0 <= x <= 50 and x % 10 == 3]bksl-nlbksl-nl

A

Z

π à Monte-Carlo

La méthode de Monte-Carlo est un ensemble de méthodes algorithmiques visant à déterminer la valeur approchée d'une constante en utilisant des procédés aléatoires.

On peut utiliser cette méthode afin de déterminer une valeur approchée de \(\pi\). L'idée est la suivante :

  • on considère un carré de \(2\) unités de côtés. Son aire vaut donc \(4\) ;
  • on considère un disque de rayon \(1\) centré au centre du carré. Son aire vaut donc \(\pi \times 1^2=\pi\) ;
  • on génère un grand nombre de points aléatoires répartis de façon uniforme dans le carré.

Il reste alors à compter le nombre de points à l'intérieur du disque. On peut montrer que leur fréquence tend vers \(\frac{\pi}{4}\) quand le nombre de points aléatoires devient très grand.

Une valeur approchée de \(\pi\) est donc :

\[\pi \approx 4 \times \frac{\text{nombre de points dans le disque}}{\text{nombre de points dans le carré}}\]

On observe ci-dessous le carré de départ ainsi que de nombreux points. On a représenté de couleur différente ceux qui sont dans le cercle et ceux qui n'y sont pas.

Méthode de Monte-Carlo

On se donne donc :

  • une liste de nb_points aléatoires, tous dans le carré décrit ci-dessus. Cette liste est nommée points et chaque point est représenté par ses coordonnées. Par exemple [(-0.5313, 0.0936), (0.9638, 0.3577), ...].

  • une fonction distance_origine prenant en argument les coordonnées x et y d'un point et renvoyant sa distance à l'origine du repère (et donc au centre du cercle)

La fonction random

Le module random de Python propose une fonction random qui génère des nombres aléatoires uniformément répartis entre 0 et 1.

Donc 2 * random() est compris entre 0 et 2 et 2 * random() - 1 entre -1 et 1.

On demande d'extraire la liste des points situés dans le cercle à l'aide d'une liste en compréhension.

Au bout de 10 essais infructueux, le corrigé vous est proposé.

###
# Testsbksl-nlattendus = [p for p in points if distancepy-undorigine(p[0], p[1]) <= 1]bksl-nlassert danspy-undcercle == attendusbksl-nlbksl-nl 10/10
from math import sqrtbksl-nlfrom random import randombksl-nlbksl-nlbksl-nldef distancepy-undorigine(x, y):bksl-nl return sqrt(x py-str x + y py-str y)bksl-nlbksl-nlbksl-nlnbpy-undpoints = 100py-und000bksl-nlpoints = [(2 py-str random() - 1, 2 py-str random() - 1) for py-und in range(nbpy-undpoints)]bksl-nlbksl-nldanspy-undcercle = ...bksl-nlbksl-nl# Affiche une valeur approchée de pibksl-nlprint(4 py-str len(danspy-undcercle) / nbpy-undpoints)bksl-nlbksl-nlfrom math import sqrtbksl-nlfrom random import randombksl-nlbksl-nlnbpy-undpoints = 100py-und000bksl-nlpoints = [(2 py-str random() - 1, 2 py-str random() - 1) for py-und in range(nbpy-undpoints)]bksl-nlbksl-nlbksl-nldef distancepy-undorigine(x, y):bksl-nl return sqrt(x py-str x + y py-str y)bksl-nlbksl-nlbksl-nlproches = [p for p in points if distancepy-undorigine(p[0], p[1]) <= 1]bksl-nlbksl-nlprint(4 py-str len(proches) / nbpy-undpoints)bksl-nlbksl-nl

A

Z