Sets
Sets are unordered collections of unique objects. In Python a set is a built-in data type, like other more common collections, such as lists, tuples and dictionaries. Sets are widely used in logic and mathematics. In Python we can take advantage of their properties to create shorter, more efficient, and more readable code.
To create a set we put its elements between braces:
We can have elements of multiple data types within a single set:
However, a set cannot contain mutable objects, like lists, dictionaries, and even other sets.
Note that sets and dictionaries are both created using braces, thus Python cannot know whether we intend to create a set or a dictionary when we say:
This assignment creates an empty dictionary. To generate an empty set, we need to use the built-in set()
function:
In the same way we can obtain a set from any iterable object:
A set can be converted to a list and vice-versa. In the latter case, repeated elements are unified (remember, sets members are unique).
Managing Elements¶
Sets are mutable objects. By using the add()
and discard()
/ remove()
methods we can insert and remove elements.
Both discard()
and remove()
serve the same purpose, but remove()
will raise a KeyError
when the argument does not exist within the set, while discard()
will just fail silently.
To determine if an element belongs to a set, we use the in
keyword.
The clear()
function removes all the elements.
The pop()
method randomly returns an element (it couldn't be any other way since the elements are not ordered). Thus, the following loop prints and removes the members of a set one by one.
pop()
throws the KeyError
exception when the set is empty.
To get the number of elements we use the well-known len()
function:
Main Operations¶
Some of the most interesting properties of sets lie in their main operations: union, intersection and difference.
The union is performed with the |
character and returns a set containing the elements found in at least one of the two sets involved in the operation.
The intersection works analogously, but with the &
operator, and returns a new set with the elements found in both sets.
The difference returns a new set containing the elements of a
that are not in b
.
Two sets are equal if and only if they contain the same elements (this is known as extensionality):
Other Operations¶
B is said to be a subset of A when all the elements of the former also belong to the latter. Python can determine this relationship via the issubset()
method.
Conversely, A is said to be a superset of B.
The definition of these two relations leads us to conclude that every set is at the same time a subset and a superset of itself.
The symmetric difference returns a new set which contains those elements which belong to one of the two sets that participate in the operation but not to both. It could be understood as an exclusive union.
Given this definition, it follows that the order of the objects is indistinct:
Finally, a set is said to be disjoint with respect to another if they do not share elements with each other.
In other words, two sets are disjoint if their intersection is the empty set, so it can be illustrated as follows:
Immutable Sets¶
frozenset
is an implementation similar to set
, but immutable. That is, it shares all the set operations provided in this post except for those that involve altering its elements (add()
, discard()
, etc.). The difference is analogous to that between a list and a tuple.
|
>>> a = frozenset({1, 2, 3})
|
|
>>> b = frozenset({3, 4, 5})
|
|
>>> a & b
|
|
frozenset({3})
|
|
>>> a | b
|
|
frozenset({1, 2, 3, 4, 5})
|
|
>>> a.isdisjoint(b)
|
|
False
|
This allows, for example, to use sets as keys in dictionaries:
Examples¶
What real use cases do sets have? Consider a program that asks the user to enter a couple of integers and outputs those which are prime.
|
# Request user input.
|
|
numbers = input("Enter numbers separated by spaces: ")
|
|
# Convert to a list of integers.
|
|
numbers = [int(n) for n in numbers.split(" ")]
|
Now, using the get_prime_numbers()
function designed in a previous post to get prime numbers, the traditional solution (using lists) would look something like this:
|
numbers = input("Enter numbers separated by spaces: ")
|
|
numbers = [int(n) for n in numbers.split(" ")]
|
|
prime_numbers = [n for n in numbers if n in get_prime_numbers(max(numbers))]
|
However, if we work with sets, the solution is even shorter and more efficient:
For this to work we need to make sure that the get_prime_numbers()
function returns a set by replacing the last line with a set comprehension (instead of a list comprehension):