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 :

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 :

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

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

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

    >>> [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
>>> "A".lower()
'a'
>>> " ".lower()
' '

Tronquer ou non le feedback dans les terminaux (sortie standard & stacktrace / relancer le code pour appliquer)
Si activé, le texte copié dans le terminal est joint sur une seule ligne avant d'être copié dans le presse-papier

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")...

Tronquer ou non le feedback dans les terminaux (sortie standard & stacktrace / relancer le code pour appliquer)
Si activé, le texte copié dans le terminal est joint sur une seule ligne avant d'être copié dans le presse-papier

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 :

    >>> [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):

    >>> 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" :

    >>> 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 :

    >>> 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 4 caractères ou moins :

    >>> 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 :

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é.

###(Dés-)Active le code après la ligne # Tests (insensible à la casse)
(Ctrl+I)
Entrer ou sortir du mode "deux colonnes"
(Alt+: ; Ctrl pour inverser les colonnes)
Entrer ou sortir du mode "plein écran"
(Esc)
Tronquer ou non le feedback dans les terminaux (sortie standard & stacktrace / relancer le code pour appliquer)
Si activé, le texte copié dans le terminal est joint sur une seule ligne avant d'être copié dans le presse-papier
Évaluations restantes : 10/10

.128013fx]gSa!:.C3/9moàcbPérhd_)wi;tsy*(254e7k8 [n%6=puzv10l050x0L0D0g0B0#0E0P0r0#0g0E0E0U010D0B0V010406050E0W0o0o0g0v0F040f0p0#0W0_0p0R050m101214160~0V041f1m051p0m1p1r1m0~0x0B0Y0.0:0=0@0w0B0e0w0#1F0w0D0|050)0s0#0L1A0;0?011E1G1I1G0D1O1Q1M0D0s0p0x161N0v1n0D0w0.190E0V0g0R0@0I011S1C010b0+0L0R0g0o0L1M1@1_1~1U211Q24260|0a0P0t0v0p0V0p0E0B1c0R0P0%1=0v0v0L0r2r1f290R1n0m1:2E0D1.1-1/0x2b0@1I0R232o1M1x1z0/1T2O0B2Q0R1*1y1M0V2x1n2C2E2,0 1^2s2W1 2#0v130#0|0P0Z2B2:0}2/2a2=1U2@2_2{0I2~1_302C2N01350g2`040P0l392D0~3c330@3f3h0P0K3l3b2:3d3r2{0J3v3n3x3p3e0p2^3g2{0T3C312;1B343H363i0M3M3o3P3q3R3J3i0O3V3E3X3G3I3s0n3%323)3z040Z0!3.3O2X3*3S0Z2}1g2 3D3/3`3;0Z383 3a413_2?3Z3h0Z3k473m3N3y4c0|0Z3u4g3w424b3+4l3B4o494j4s3=3L4v4i3F443U4B3W434k3=3$4G3(4I4y0Z3-4M4q3Q4y0I3@4S4a4U3S0I3~2,4w4D4J0I464(4C3:4+4f4.4H4r4#4n4?4N4^3!0I4u4{4T3Y4V4A514Z534#4F564x4#4L5b4*4V4R5f4:4y0l4X5j4O3S0l4%404/5p3!0l4-2 1o2*1f2U2H0x2L3d0r1*271n5D1q5B2.4o055I0%2+4|1U0r0Z0|030P1I0E0D0L0y0Z1=0R0_230D5#0L0-0Y3g0L0W0v0-5%0v0B2z0L265-0P2n2p0_0Y5=2t1R2#0o0s2x0E3^3y0|5$5(5*3v0P5u1 0p0|0U6n6p1U0{040Q3v6v3q0|0c6u4@1U0N0|0b3H6F5V6C046E4o6o6G0@0p0A0|2Z6M523e0|6c6e5=6Z57016I040B0b6*6i6P6;3F6r04020e0D0C6@3)0o0B0|5n5z6T016x0d3C4)3)5X5Z5#0B5%5)0I5,5.631Q5?5^5`0-2Z0b0u5~5_6f0P0p0W0P0u0e5^0-0q2|0!6a0P6%6f6h4D6j7g6l5y3a6S6N016_6t6R6B770|6z5Q760R6D6 3`6-6K0v7,2?7+7Z766V6X1e7@7V7*047L6)7|6!6-6/7;347?2,7U6!6_020#6}7Y897!714l743a7!787a7!7d045!6k5)0l7k0B5/5;7o1Q7q0P0B0o1^0B7x2u806g4Y6=8u0y4=2 8a6+7X860@6x7%2.7)888S7!7.6L826+7~6Q8h7^6W6.7{8/7}6$0p6d7M8+3d846:8}7O6?913)6_0S8W018j047S2D8T3d7X8g8%769a5s8m768o4v7b3`8r8t7Q5)0K8x8z7n0P5@8C5{2t1y7g0B1P691^0v0P0M7J8L7N3:7P7h0y4`9i7V8V943`8Y6A8#938@836J8*9)8,8$7T7!7_8=987~9P9Z1 8 9@9/9d9;0|979`1U9a5a9W8b6s9h9:9j72048l2D8n0|799p8q5Y8s7f9T0J9x7m699B7w0-2#2s2U9G9I0-9K0Paq8K8`6(8M5o7=048P50a78U6s989#7(8^9(aP8~9+7:a36O8.aX6^8;6Ya#6#7 aH8|9-aY6.90a;92a%ab9Xa1989aaOa{a8040haa9 ac739$7V9o4(9q1 9sao6l0Tar5:9zau8D0x1dbk1R2I0`1Q0P5=0D9Q9ram5!7s7u8y5`7y7A7C3g0P7G0Z0J7IaG8{81aK87aM9u0y55a(95aRa,aT8!aVa`b67V8)a!a^9RaWb18Ua*8?bY438_bQaJb^9{6Xa@b}a4ad8Rb;9f0|0G9}b:b*b28d8fa~adbMaf5U6!bb40bd5WbAbg5)9N5I5-8yas8Bav640*7x0(7KbI6769bPaIbyaL8Pa6c56^b!b.9!7$b96!8-98b,c9b)3i9;b?c99_cQb~a?cY9896cf0|9cc!7^a9c/aec-8;1_0xc,a,8c8e0Cb5c=7V9aciah04ajbcal7e8P0Obj8A9A7p9D8H7x7zcD7DcF0-cHa:5t9%dec-cPc18XcSaUcU9~d49*047/c~c)1U9=a+dK6Oc(dz6,b dJdRc.a,9ac;9ecO040Ud3d!70adcid)3`9=9,dRcVc 0|cdd2c^d79nai8p76bf8P0ndgbldjdrbp5;0.1E0b0b2x6a0-0W0R2q0u0-bw9McJco7e0k1d0E0L0+0P0i2j23es0XbK0Peg0P0o1*0W0#0p0P0H0c0P0S0P0jeQ0Pd%ePeQ0z9Oa/bRduaVe1dxd$aSdBb%dDcadF6+cXa,d=dO7Wc$e;b`cIa,9|e_e-d-6qa}dXcgd,a0d$d(8iadcMagd|d9d~7Ve0bV3?e3ate51=8G5~esek5-ed7I0H2Z0/0W0EeWcCbNeKfw1afzen0@bfcCboase96/ec1R0%efeh0Dejbv5%3jeXb{fHa-8P3?e%f8fd8Z75b(cWaZdUcN95e^e?9^eYb|f=7-dTf3b8d?6`d1f*f.g1d^g46!a f58:0|c|f;cbaQ04a2e?9kgba|f7c^c4fcbad}4B0m5S0L2E2)gx5C1y5E2H2J2F1)1+2H0g9I2E5D0~0m0%0)0+0E04.
π à 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é.

###(Dés-)Active le code après la ligne # Tests (insensible à la casse)
(Ctrl+I)
Entrer ou sortir du mode "deux colonnes"
(Alt+: ; Ctrl pour inverser les colonnes)
Entrer ou sortir du mode "plein écran"
(Esc)
Tronquer ou non le feedback dans les terminaux (sortie standard & stacktrace / relancer le code pour appliquer)
Si activé, le texte copié dans le terminal est joint sur une seule ligne avant d'être copié dans le presse-papier
Évaluations restantes : 10/10

.128013,f]gSa0/mocPrhd_wi;tsy(2lek [n=puv1)b050p0A0u0g0s0z0v0C0l0z0g0v0v0F010u0s0G010406050v0H0j0j0g0n0w040f0k0z0H0$0k0E050i0-0/0;0?0+0G040 1605190i191b160+0p0s0I0U0W0Y0!0o0s0e0o0z1p0o0u0)050P0L0z0A1k0X0Z011o1q1s1q0u1y1A1w0u0L0k0p0?1x0n170u0o0U0_0v0G0g0E0!0y011C1m010c0R0A0E0g0j0A1w1!1$1+1E1.1A1;1?0)0a0C0m0n0k0G0k0v0s0|0E0C0N1Y0n0n0A0l2b0 1_0E170i1W2o0u1U1T1V0p1{0!1s0E1:281w1h1j0V1D2y0s2A0E1Q1i1w0G2h172m2o2S0,1#2c2G1,2L0n0:0z0)0J2l2W2o2P0A2o2E2r0p2v2x010l1Q1@172:1a2Q2V1$2T2+052_0N2R2W2@0E0)0p1$0v0q0l0A0n0V0A2*310C302X1l1E0k0)0F3l2n3n2m2@0(040D3v371`2Y1E3a040G3D3x383G0!0B0)0c0k0n3L3o390)3K102+3M3F3q0!0k0r0)2J3V3y3O013I272J0u0v3.3N3(013Q040s0c3`3%2H3;3b0s0v0P0E3g0q3T1p2J3k3!313W3:3A0x3D4j3|3=4n3/3|3A3C4h2n4o440j0s0)0h4r3{443A0d0b423p444q4w3E4L1,4u4E431,4A2(4T4Q1E4H0K4K2@3s04020z0u0t3u4O3$4Z0!4W042)4O4y4R0)0d3D0+0i352.182 0i2}2p2=0 2s2r1P1R2r0g1z53561i0*0 0N0P0R0v04.