{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "0e7d133b",
   "metadata": {},
   "source": [
    "# Séance 3\n",
    "\n",
    "\n",
    "```{admonition} Objectifs\n",
    "* Compléments sur les listes\n",
    "* Ensembles et dictionnaires\n",
    "* Mot-clefs **`all`** et **`any`**\n",
    "```\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "## Déclaration de liste par compréhension\n",
    "\n",
    "Le langage python permet de construire des listes avec une **syntaxe proche des mathématiques**. Supposons que l'on souhaite créer la liste des entiers compris entre $0$ et $33$, qui sont des multiples de $3$. Mathématiquement, l'ensemble des éléments de cette liste pourrait être décrit selon les deux manières suivantes :\n",
    "\n",
    "$$\n",
    "\\{\\, 3i \\mid 0 \\le i \\le 11 \\,\\} \\quad \\text{ et } \\quad \\{\\, n \\in [0, 33] \\mid n \\equiv 0 \\!\\!\\!\\mod 3 \\,\\}\n",
    "$$\n",
    "\n",
    "Avec python, on va pouvoir déclarer la liste de ces éléments d'une manière similaire. D'une part"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "8a09aa62",
   "metadata": {},
   "outputs": [],
   "source": [
    "L = [ 3 * i for i in range(0, 12) ]\n",
    "print(L)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "01c9cc85",
   "metadata": {},
   "source": [
    "et d'autre part"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "4ffb6071",
   "metadata": {},
   "outputs": [],
   "source": [
    "M = [ n for n in range(0, 34) if n % 3 == 0 ]\n",
    "print(M)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "47538538",
   "metadata": {},
   "source": [
    "Généralement, ce type de déclaration de liste s'appelle une **déclaration par compréhension**. La syntaxe est la suivante :\n",
    "```\n",
    "[ <expression(x)> for x in <structure> ]\n",
    "```\n",
    "où `<expression(x)>` est une expression qui peut dépendre d'une variable `x`, dont la portée reste locale à la liste, et qui varie dans `<structure>`, un objet itérable (par exemple une autre liste, un itérateur `range`, etc.).\n",
    "\n",
    "Voici d'autres exemples :"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "48d0a51f",
   "metadata": {},
   "outputs": [],
   "source": [
    "A = [i for i in range(7)]\n",
    "print(\"A =\", A)\n",
    "\n",
    "B =  [i**2 for i in range(-3, 4)]\n",
    "print(\"B =\", B)\n",
    "\n",
    "C = [x + 1 for x in B]\n",
    "print(\"C =\", C)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5ccb6e9d",
   "metadata": {},
   "source": [
    "Par ailleurs, on a vu dnas l'exemple plus haut que l'on peut ajouter une **condition** après la description de l'itérateur : \n",
    "```\n",
    "[ <expression(x)> for x in <structure> if <condition sur x> ]\n",
    "```\n",
    "\n",
    "où `<condition sur x>` est une condition sur `x` qui doit être vérifiée pour que l'élément `<fonction de x>` soit inclus dans la liste. Exemples :"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "e2fab463",
   "metadata": {},
   "outputs": [],
   "source": [
    "L = [i for i in range(10) if i % 2 == 0]\n",
    "print(L)\n",
    "\n",
    "MOTS = [\"bonjour\", \"maison\", \"ecole\",  \"voiture\", \"telephone\"]\n",
    "M = [ mot + \"!\" for mot in MOTS if len(mot) == 7]\n",
    "print(M)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1f926fbf",
   "metadata": {},
   "source": [
    "## Mots-clefs `any` et `all`\n",
    "\n",
    "\n",
    "Le mot-clef **`all`** permet de tester si **toutes** les valeurs logiques d'une séquence sont vraies. Par exemple, pour vérifier que tous les entiers d'une liste sont pairs, on peut écrire :"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "3a73a658",
   "metadata": {},
   "outputs": [],
   "source": [
    "L = [6, 12, -4]\n",
    "all((x % 2 == 0) for x in L)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b4dd407c",
   "metadata": {},
   "source": [
    "Ci-dessus, on observe que **`all`** prend en entrée une séquence de valeurs logiques. On peut également lui passer en entrée une **liste** de booléens :"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "db306128",
   "metadata": {},
   "outputs": [],
   "source": [
    "M = [\"mot\", \"clef\", \"all\"]\n",
    "all([ len(x) == 3 for x in M ])"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b14d333b",
   "metadata": {},
   "source": [
    "Le mot-clef **`any`** teste si **au moins une** des valeurs logiques passées en paramètre est vraie :"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "8d2dc6bf",
   "metadata": {},
   "outputs": [],
   "source": [
    "M = [\"mot\", \"clef\", \"all\"]\n",
    "any(len(x) == 4 for x in M)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a3e76548",
   "metadata": {},
   "source": [
    "Un autre exemple :"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "a4bace2b",
   "metadata": {},
   "outputs": [],
   "source": [
    "L = [6, 12, -4]\n",
    "any(x % 2 == 1 for x in L)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5e47a8a5",
   "metadata": {},
   "source": [
    "Enfin, confomément aux conventions classiques de logique, pour la **liste vide**, on a respectivement :"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "e090a572",
   "metadata": {},
   "outputs": [],
   "source": [
    "all([]), any([])"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "75bb38a8",
   "metadata": {},
   "source": [
    "## Ensembles\n",
    "\n",
    "### Création\n",
    "\n",
    "La liste n'est pas la seule structure de données permttant de rassembler des informations. Python permet également de manipuler des **ensembles** et des **dictionnaires**.\n",
    "\n",
    "En informatique, un **ensemble** peut être vu comme en mathématiques : c'est une collection **non-ordonnée** d'éléments **distincts**.\n",
    "\n",
    "Pour créer un ensemble, on utilise les accolades (comme en mathématiques) :"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "94562b84",
   "metadata": {},
   "outputs": [],
   "source": [
    "{ 1, 3 }"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "20b1580c",
   "metadata": {},
   "source": [
    "L'ensemble vide peut être construit par la commande `set()` et représenté par `{}`.\n",
    "\n",
    "Comme expliqué précédemment, python stocke un ensemble de manière désordonnée et élimine des potentiels doublons :"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "e3fb6681",
   "metadata": {},
   "outputs": [],
   "source": [
    "A = { 3, 1, \"a\", 1 }\n",
    "print(A)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c252fcb9",
   "metadata": {},
   "source": [
    "### Opérations élémentaires\n",
    "\n",
    "\n",
    "Comme un ensemble n'est pas ordonné, on ne peut pas accéder à son \"élément d'indice $i$\". Néanmoins, on peut **ajouter**, **retirer** et **tester l'appartenance** d'un élément à l'ensemble :"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "cae9b18e",
   "metadata": {},
   "outputs": [],
   "source": [
    "S = { 0, 1, 2 }\n",
    "print(S)\n",
    "\n",
    "S.add(\"ajout\")\n",
    "print(S)\n",
    "\n",
    "S.remove(0)\n",
    "print(S)\n",
    "\n",
    "print(1 in S)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e782d576",
   "metadata": {},
   "source": [
    "Il est possible de passer d'une liste à un ensemble avec les commandes `list` et `set`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "0136ddff",
   "metadata": {},
   "outputs": [],
   "source": [
    "B = { 3, 2, 1 }\n",
    "L = list(B)\n",
    "S = set(L)\n",
    "\n",
    "print(B)\n",
    "print(L)\n",
    "print(S)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e603f418",
   "metadata": {},
   "source": [
    "Enfin, il existe des opérations classiques sur les ensembles :"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "2e7cb06b",
   "metadata": {},
   "outputs": [],
   "source": [
    "A = { 0, 1, 2 }\n",
    "B = { 3, 2, 1 }\n",
    "print(\"Union :\", A.union(B))\n",
    "print(\"Intesection :\", A.intersection(B))\n",
    "print(\"Différence symétrique :\", A.symmetric_difference(B))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2d854102",
   "metadata": {},
   "source": [
    "**Tableau récapitulatif (ensemble)**\n",
    "\n",
    "| Opération sur l'ensemble $S$ | Syntaxe python |\n",
    "| :---: | :---: |\n",
    "| affectation à l'ensemble vide | `S = set()` |\n",
    "| affectation à l'ensemble $\\{1, 2, 7 \\}$ | `S = { 7, 1, 2}`  (par exemple) |\n",
    "| ajout d'un élément $x$ | `S.add(x)` |\n",
    "| suppression d'un élément $y$ | `S.remove(y)` |\n",
    "| union avec un ensemble $T$ | `S.union(T)` |\n",
    "| intersection avec un ensemble $T$ | `S.intersection(T)` |\n",
    "| différence symétrique avec un ensemble $T$ | `S.symmetric_difference(T)` |\n",
    "| test d'appartenance de $y$ | `y in S` |\n",
    "\n",
    "\n",
    "Attention, les éléments d'un ensemble python ne peuvent pas être de n'importe quel type : le type doit être **hachable** (donc, en particulier, **immutable**). Pour plus d'informations pour cette notion avancée, voir [ici](https://zestedesavoir.com/tutoriels/954/notions-de-python-avancees/1-starters/3-mutables-hashables). Par exemple, on ne peut pas placer une liste dans un ensemble."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "b15ea20c",
   "metadata": {},
   "outputs": [],
   "source": [
    "{ [1, 2] }"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "63d61278",
   "metadata": {},
   "source": [
    "Enfin, les ensembles supportent la **déclaration par compréhension** (vous remarquerez que l'ordre d'affichage peut ne pas respecter l'ordre de construction) :"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "d9e3bce2",
   "metadata": {},
   "outputs": [],
   "source": [
    "{ -x for x in range(12) }"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "df54f0dc",
   "metadata": {},
   "source": [
    "## Dictionnaires\n",
    "\n",
    "\n",
    "### Création\n",
    "\n",
    "Un **dictionnaire** est une structure de données plus complexe, qui peut être grossièrement vue comme la **généralisation d'une liste**, où les indices des éléments sont des valeurs quelconques au lieu d'être fixés à $0, 1, \\dots, n-1$.\n",
    "\n",
    "\n",
    "Par exemple, supposons que l'on souhaite créer une structure de données qui associe à certains mots leurs longueur. On va créer un dictionnaire avec la syntaxe est suivante :"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "3a5f619f",
   "metadata": {},
   "outputs": [],
   "source": [
    "D = { \"lundi\" : 5, \"mardi\" : 5, \"mercredi\" : 8, \"jeudi\" : 5, \"vendredi\" : 8, \"samedi\" : 6, \"dimanche\" : 8 }\n",
    "print(D)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ba3862b2",
   "metadata": {},
   "source": [
    "Les mots \"lundi\", \"mardi\", \"mercredi\", etc. sont appelées les **clés** du dictionnaire, et les entiers $5$, $5$, $8$, etc. sont les **valeurs** correspondantes. Ainsi, la syntaxe générale pour déclarer un dictionnaire est la suivante \n",
    "```\n",
    "{ \n",
    "  clé1 : valeur1,\n",
    "  clé2 : valeur2,\n",
    "  clé3 : valeur3\n",
    "  ...\n",
    "  }\n",
    "```\n",
    "Comme pour les ensembles, les clés d'un dictionnaire doivent être **hachables**, donc, en particulier, une liste ne peut pas être une clé d'un dictionnaire.\n",
    "\n",
    "\n",
    "### Opérations élémentaires\n",
    "\n",
    "Si `D` est un dictionnaire, on **accède** à la valeur correspondant à une clé `k` par `D[k]` (exactement comme avec une liste) :"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "a7fc6817",
   "metadata": {},
   "outputs": [],
   "source": [
    "D[\"jeudi\"]"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "96c317ee",
   "metadata": {},
   "source": [
    "On peut **ajouter** un couple clé/valeur avec la syntaxe `D[clé] = valeur`, par exemple :"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "19817fcc",
   "metadata": {},
   "outputs": [],
   "source": [
    "D[\"jour\"] = 4\n",
    "print(D)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "77344c47",
   "metadata": {},
   "source": [
    "Si la clé existait déjà dans le dictionnaire, cet ajout **écrase** la valeur précédente. Cette syntaxe vaut donc également pour **modifier** la valeur associée à une clé.\n",
    "\n",
    "\n",
    "Puis, pour **retirer** un élément d'un dictionnaire, on peut utiliser la méthode `pop` (comme pour les listes) :"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "0fefcc75",
   "metadata": {},
   "outputs": [],
   "source": [
    "D.pop(\"jour\")\n",
    "print(D)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f2d7fbee",
   "metadata": {},
   "source": [
    "On peut **tester l'appartenance** d'une **clé** à un dictionnaire avec le mot-clé **`in`**, et itérer sur les clés d'un dictionnaire avec la structure **`for ... in ...:`**."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "864d72b7",
   "metadata": {},
   "outputs": [],
   "source": [
    "print(\"monday\" in D)\n",
    "\n",
    "for x in D:\n",
    "    print(\"Le mot\", x, \"possède\", D[x], \"lettres.\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "46fcbcce",
   "metadata": {},
   "source": [
    "**Tableau récapitulatif (dictionnaire)**\n",
    "\n",
    "| Opération sur le dictionnaire $D$ | Syntaxe python |\n",
    "| :---: | :---: |\n",
    "| affectation au dictionnaire vide | `D = dict()` |\n",
    "| affectation à un dictionnaire non-vide | `D = { \"a\": 1, \"bcd\": 7 }`  (par exemple) |\n",
    "| accès à la valeur associée à la clé $c$ | `D[c]` |\n",
    "| ajout d'un couple clé/valeur $(c,v)$ | `D[c] = v` |\n",
    "| modification d'un couple clé/valeur en $(c,v)$ | `D[c] = v` |\n",
    "| suppression de l'élément de clé $c$ | `D.pop(c)` |\n",
    "| test d'existence d'une clé $c$ | `c in D` |\n",
    "\n",
    "\n",
    "\n",
    "Enfin, un dictionnaire python peut être **déclaré par compréhension** :"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "0561cfa8",
   "metadata": {},
   "outputs": [],
   "source": [
    "L = [\"lundi\", \"mardi\", \"mercredi\", \"jeudi\", \"vendredi\", \"samedi\", \"dimanche\"]\n",
    "E = { jour : len(jour) for jour in L }\n",
    "print(E)\n",
    "print(E == D)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "python",
   "language": "python",
   "name": "python"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
