Sets

Comme les dictionnaires, les sets sont des collections d'éléments non-ordonnées.

Dans un set, chaque élément doit être unique et immuable, c’est-à-dire qu'il ne peut pas être modifié.

On peut donc stocker des chaînes de caractères, des nombres et des tuples dans un set mais pas de listes ou de dictionnaires !

En revanche, le set en lui-même peut être modifié ! On peut y ajouter des objets et aussi en supprimer.

Les sets sont souvent utilisés pour contrôler les doublons et effectuer des opérations sur les ensembles comme les unions, les différences, les intersections, etc.

Créer un set

Il existe deux façons de créer un set en Python.

La première consiste à utiliser la fonction set() :

#norun
s = set(iterable)

Lorsque vous définissez un set avec cette fonction, vous devez passer un objet itérable comme une liste, un tuple ou une chaîne de caractères :

#norun
s = set() # Set vide
s = set(['spam', 'eggs', 'knights', 'ham']) # {'ham', 'knights', 'spam', 'eggs'}
s = set(('spam', 'eggs', 'knights', 'ham')) # {'ham', 'knights', 'spam', 'eggs'}
s = set('eggs') # {'e', 's', 'g'}

Je peux passer une liste en argument alors que c'est un objet muable. Cependant, la fonction set() retourne bien un set dans lequel la liste a été décomposée en chaînes de caractères, qui elles, sont bien des objets immuables 🙂

L'autre manière de faire est d'utiliser les accolades {} :

#norun
s = {item1, item2, item3}
s = {'spam', 'eggs', 'knights'} # {'spam', 'eggs', 'knights'}

Chaque objet passé entre les accolades devient un item distinct du set, que cet objet soit itérable ou non.

C'est ce qui différencie les deux méthodes de création d'un set !

Par exemple :

#norun
s = set('eggs')  # {'e', 's', 'g'} => Itérable où chaque élément est évalué
s = {'eggs'}     # {'eggs'}        => Reste un élément distinct du set
Les accolades sont également utilisées pour créer des dictionnaires. Python comprend tout seul s'il s'agit d'un dictionnaire ou d'un set grâce aux éléments entre les accolades. Dans le cas d'un dictionnaire, on retrouve des paires de clés: valeurs alors que dans un set on retrouve uniquement des objets séparés par une virgule.

Modifier un set

Les sets étant désordonnés, on ne peut pas accéder aux éléments qu'ils contiennent grâce à un index :

#norun
s = {'spam', 'eggs', 'knights'}
print(s[0])  # TypeError: 'set' object is not subscriptable

Pour rappel, on ne peut pas modifier les éléments d'un set car ils sont immuables !

Du coup, Python met à notre disposition deux méthodes pour ajouter des éléments à l'intérieur d'un set !

Ajouter un élément avec add(objet) :

s = {'spam', 'eggs', 'knights'}
s.add('ham') 
print(s) # {'ham', 'knights', 'spam', 'eggs'}

Met à jour le set avec les éléments contenus dans l'itérable avec update(iterable) :

s = {'spam', 'eggs', 'knights'}
s.update(['ham', 'lumberjack', 'bones'])
print(s)  # {'ham', 'bones', 'lumberjack', 'spam', 'eggs', 'knights'}

Retirer certains éléments d'un set

On peut retirer les éléments d'un set grâce aux méthodes discard et remove.

La méthode discard ne modifie pas le set si l'élément à supprimer n'est pas présent dans le set à l'inverse de remove qui lèvera une exception :

#norun
s = {'ham', 'bones', 'lumberjack', 'spam', 'eggs', 'knights'}
print(s) # {'ham', 'bones', 'lumberjack', 'spam', 'eggs', 'knights'}

s.discard('bones')
print(s) # {'ham', 'lumberjack', 'spam', 'eggs', 'knights'}

s.remove('eggs')
print(s) # {'ham', 'lumberjack', 'spam', 'knights'}

s.discard('anything')
print(s) # {'ham', 'lumberjack', 'spam', 'knights'}

s.remove('anything') # KeyError: 'anything'

Vous pouvez aussi vider complètement un set avec la méthode clear :

#norun
s = {'ham', 'bones', 'lumberjack', 'spam', 'eggs', 'knights'}
s.clear()  # set()
Même si le set a été créé en utilisant les accolades, la méthode clear retourne set() et non {} (car des accolades vides correspondent à un dictionnaire).

Les opérations possibles sur un set

Les sets peuvent être utilisés pour réaliser des opérations mathématiques comme des unions, des différences, des intersections ou encore des différences symétriques.

Union

Une union entre A et B crée un set avec tous les éléments de A et de B.

Pour créer cette union, on utilise le symbole (on peut aussi utiliser la méthode union) :

A = {1, 2, 3, 4, 5}
B = {6, 7, 8, 9, 10}

print(A | B)       # {1, 2, 3, 4, 5, 6, 7, 8, 9,10}
print(A.union(B))  # {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}

Intersection

Une union entre A et B crée un set avec tous les éléments communs de A et de B.

Pour créer cette intersection, on utilise le symbole & (on peut aussi utiliser la méthode intersection) :

A = {3, 4, 5, 6, 7}
B = {6, 7, 8, 9, 10}

print(A & B)              # {6, 7}
print(A.intersection(B))  # {6, 7}

Différence

Une différence de A sur B crée un set avec tous les éléments uniquement compris dans A mais pas dans B.

Pour créer cette différence, on utilise le symbole - (on peut aussi utiliser la méthode difference) :

A = {1, 2, 3, 4, 5}
B = {4, 5, 6, 7, 8}

print(A - B)            # {1, 2, 3}
print(A.difference(B))  # {1, 2, 3}

Différence symétrique

Une différence symétrique entre A et B crée un set avec tous les éléments compris dans A et dans B mais pas dans les deux à la fois.

Pour créer cette différence, on utilise le symbole ^ (on peut aussi utiliser la méthode symmetric_difference) :

A = {1, 2, 3, 4, 5}
B = {4, 5, 6, 7, 8}

print(A ^ B)                      # {1, 2, 3, 6, 7, 8}
print(A.symmetric_difference(B))  # {1, 2, 3, 6, 7, 8}

Frozenset

Les frozenset ont exactement les mêmes caractéristiques qu'un set classique à la différence qu'ils ne peuvent plus être modifiés une fois créés.

On les définit en utilisant la fonction frozenset() :

#norun
s = frozenset(['bones', 'lumberjack', 'spam', 'eggs', 'knights'])

print(s)               # frozenset({'knights', 'spam', 'lumberjack', 'bones', 'eggs'})
print(len(s))          # 5
print(s.add('bones'))  # AttributeError: 'frozenset' object has no attribute 'add'