.. _tut-sets: ******** Les sets ******** Une vidéo de présentation des ensembles... .. raw:: html Les :class:`set` sont des containers mutables non ordonnés qui possèdent les caractéristiques des ensembles mathématiques. En particulier, ils ne disposent pas d'éléments dupliqués. Ils se définissent à partir des opérateurs ``{`` et ``}`` ou du constructeur :class:`set`:: >>> foot = set(['Angers', 'Bordeaux', 'Brest', 'Dijon', 'Lens', 'Lille', 'Lorient', 'Lyon', 'Marseille', 'Metz', 'Monaco', 'Montpellier', 'Nantes', 'Nice', 'Nimes', 'Paris', 'Reims', 'Rennes', 'Saint - Étienne', 'Strasbourg']) >>> len(foot) 20 L'ordonnancement n'a pas de sens pour un :class:`set` et n'est pas prédictible:: >>> foot {'Marseille', 'Lille', 'Metz', 'Rennes', 'Nice', 'Nantes', 'Nimes', 'Strasbourg', 'Bordeaux', 'Dijon', 'Montpellier', 'Brest', 'Lorient', 'Reims', 'Lens', 'Paris', 'Monaco', 'Angers', 'Lyon', 'Saint - Étienne'} Comme la :class:`list`, le :class:`set` est une séquence **mutable**. Il dispose donc de toutes les méthodes correspondantes à ce type de séquence. On peut donc en particulier le modifier une fois créé, par exemple retirer des éléments avec la méthode :meth:`~frozenset.remove`:: >>> foot.remove('Metz') >>> len(foot) 19 ou en ajouter avec la méthode :meth:`~frozenset.add`:: >>> foot.add('Metz') >>> len(foot) 20 .. note:: La sémantique est importante : - Une :class:`list` étant un container ordonné, ajouter un élément c'est le placer à la fin, et à cette fin, on utilise le verbe :meth:`~list.append` ; - Un :class:`set` étant un container non ordonné, ajouter un élément ne donne pas d'information de position, et à cette fin, on utilise le verbe :meth:`~frozenset.add`. Le constructeur :class:`set` prend en argument une séquence (une :class:`list` pour ce qui concerne l'exemple ci dessus). Cette séquence peut éventuellement contenir des éléments dupliqués. Les doublons sont automatiquement éliminés. .. admonition:: A expérimenter... Une chaîne de caractères (:class:`str`) est une séquence et peut être utilisée pour construire un :class:`set`. Conjecturer le résultat de l'opération suivante:: >>> f = set('football') Vérifier dans un interpréteur interactif. Le :class:`set` est un conteneur non ordonné. La position ou l'ordre d'insertion des éléments n'est pas enregistré. En conséquence, les opérations d'indexation ou de slicing ne sont pas supportées:: >>> f[0] Traceback (most recent call last): File "", line 1, in TypeError: 'set' object does not support indexing Les :class:`set` ne peuvent contenir que des objets immutables, dont la structure ne peut pas être modifiée après création. Ces objets sont dits "hashables". Les exemples ci dessus utilisent des chaînes de caractères. On peut également créer des :class:`set` de nombres entiers:: >>> s = {0, 1, 2, 3, 4} >>> s {0, 1, 2, 3, 4} Si l'on tente d'insérer un objet mutable dans un :class:`set`, une exception de type ``TypeError`` est générée:: >>> s = {0, 1, 2, [3, 4]} Traceback (most recent call last): File "", line 1, in TypeError: unhashable type: 'list' Appartenance ============ Comme toutes les séquences, les :class:`set` disposent de l'opérateur :keyword:`in`:: >>> basket = set(['Boulazac', 'Bourg-en-Bresse', 'Chalon/Saône', 'Cholet', 'Reims', 'Dijon', 'Gravelines', 'Levallois', 'Le Mans', 'Le Portel', 'Limoges', 'Monaco', 'Nanterre', 'Orléans', 'Pau', 'Roanne', 'Strasbourg', 'Villeurbane']) >>> 'Limoges' in basket True >>> 'Limoges' in foot False Itérer sur un set =================== Le :class:`set` étant également une séquence, l'opérateur :keyword:`in` est utilisé pour l'itération:: >>> for elt in f: ... print(elt) ... a b o f t l Puisque le :class:`set` ne supporte pas l'indexation, on ne peut itérer que sur les éléments. Inutile donc ici de préciser une bonne pratique, contrairement aux :class:`str`, :class:`list` et :class:`tuple`. Opérations ensemblistes ======================= Les :class:`set` disposent d'opérations ensemblistes puissantes et rapides : - intersection - union - différence - inclusion - etc... >>> rugby = set(['Agen', 'Bayonne', 'Bordeaux', 'Brive', 'Castres', 'Clermont', 'La Rochelle', 'Lyon', 'Montpellier', 'Pau', 'Racing 92','Paris', 'Toulon', 'Toulouse']) La méthode :meth:`~frozenset.intersection` est utilisée pour calculer l'intersection de deux ou plusieurs :class:`set`. L'opérateur ``&`` permet une écriture plus lisible:: >>> foot & rugby # intersection {'Paris', 'Montpellier', 'Bordeaux', 'Lyon'} La méthode :meth:`~frozenset.union` est utilisée pour calculer l'union de deux ou plusieurs :class:`set`. L'opérateur ``|`` permet une écriture plus lisible:: >>> foot | rugby {'Marseille', 'Monaco', 'Lille', 'Metz', 'Dijon', 'Pau', 'Agen', 'Clermont', 'Montpellier', 'Racing 92', 'Rennes', 'Bayonne', 'Brive', 'Nice', 'Nantes', 'Brest', 'Toulouse', 'Lorient', 'Castres', 'Nimes', 'La Rochelle', 'Reims', 'Lens', 'Paris', 'Toulon', 'Strasbourg', 'Angers', 'Lyon', 'Saint - Étienne', 'Bordeaux'} La méthode :meth:`~frozenset.difference` est utilisée pour calculer la différence de deux ou plusieurs :class:`set`. L'opérateur ``-`` permet une écriture plus lisible:: >>> rugby - foot - basket # difference {'Toulouse', 'Castres', 'Agen', 'Clermont', 'La Rochelle', 'Racing 92', 'Toulon', 'Bayonne', 'Brive'} La méthode :meth:`~frozenset.symetric_difference` est utilisée pour calculer la différence symétrique (des éléments appartenant à l'un ou à l'autre mais pas aux deux) de deux :class:`set`. L'opérateur ``^`` permet une écriture plus lisible:: >>> rugby ^ foot {'Marseille', 'Monaco', 'Lille', 'Metz', 'Dijon', 'Pau', 'Agen', 'Clermont', 'Racing 92', 'Rennes', 'Bayonne', 'Brive', 'Nice', 'Nantes', 'Brest', 'Toulouse', 'Lorient', 'Castres', 'Nimes', 'La Rochelle', 'Reims', 'Lens', 'Toulon', 'Strasbourg', 'Angers', 'Saint - Étienne'} Pour une meilleure compréhension de la manipulation des :class:`set`, on consultera `les méthodes `_ dédiées. Les 'set comprehension' ========================= Comme pour :ref:`les listes `, on peut construire un :class:`set` de façon concise avec un ``set comprehension`` :: >>> {x*y for x in {1,2,3} for y in {2,3,4} if x != y} {2, 3, 4, 6, 8, 12} Chaque fois que ce sera possible cette syntaxe devra être utilisée. Ce qu'il faut retenir ===================== .. quiz:: quizz-09 :title: Les sets - :quiz:`{"type":"TF","answer":"F"}` Un set se délimite avec ``[`` et ``]`` - :quiz:`{"type":"TF","answer":"F"}` Un set se délimite avec ``(`` et ``)`` - :quiz:`{"type":"TF","answer":"T"}` Un set se délimite avec ``{`` et ``}`` - :quiz:`{"type":"TF","answer":"T"}` Un set peut contenir des objets hétérogènes - :quiz:`{"type":"TF","answer":"F"}` Un set peut contenir des objets *mutables* - :quiz:`{"type":"TF","answer":"T"}` Un set est *mutable* - :quiz:`{"type":"TF","answer":"F"}` Un set est une collection ordonnée - :quiz:`{"type":"TF","answer":"F"}` Les opérations de slicing sur un set sont possibles - :quiz:`{"type":"TF","answer":"F"}` Une fois créée, la taille d'un set est figée - :quiz:`{"type":"FB","answer":"add", "size":5}` est une méthode permettant d'insérer un élément dans un set - :quiz:`{"type":"TF","answer":"F"}` Il est possible d'insérer un élément à la fin d'un set - :quiz:`{"type":"FB","answer":"remove", "size":5}` est une méthode permettant de supprimer un élément d'un set - :quiz:`{"type":"TF","answer":"T"}` Le constructeur d'un set prend en paramètre une séquence - :quiz:`{"type":"TF","answer":"F"}` Le slicing peut être utilisé pour extraire des éléments d'un set - :quiz:`{"type":"TF","answer":"F"}` Le slicing peut être utilisé pour insérer des éléments dans un set - :quiz:`{"type":"TF","answer":"T"}` Sur un set, l'opérateur d'appartenance ``in`` fonctionne comme pour toute séquence - :quiz:`{"type":"TF","answer":"T"}` On peut parcourir un set en itérant sur ses éléments - :quiz:`{"type":"TF","answer":"F"}` On peut parcourir un set en itérant sur l'index de ses éléments - :quiz:`{"type":"TF","answer":"F"}` Un set peut contenir n'importe quel objet Python - :quiz:`{"type":"TF","answer":"F"}` On peut construire des sets imbriqués - Un :quiz:`{"type":"FB","answer":"set comprehension", "size":18}` est une façon concise de construire un set