Set Types

Indices and tables

Definition

In Python, a set is a container type that stores an unordered set of zero or more references to hashable objects.

Values must always be unique within the set, but, need not be the same type. An attempt to add a value that is already present will result in it being discarded (which is useful for removing duplicates from a sequence).

Sets support the typical membership test using in, as well as several additional tests based on set theory like union, intersection, difference and symmetric difference.

Set

MUTABILITY: Mutable

A set is the mutable brother of the frozenset type.

Sets can be constructed in a variety of ways:

  • Using curly brackets {}. For example:

    >>> foo = {'a', 'b', 'c', 99, 'b', 'a', 'z'}
    >>> foo
    {99, 'a', 'b', 'c', 'z'}
    

    Note

    It is not possible to create an empty set using the curly brackets {} as that syntax would create a dict.

  • Using an expression in curly brackets {} to create a set comprehension. For example:

    >>> foo = {x for x in 'foobarbaz' if x in 'fb'}
    >>> foo
    {'b', 'f'}
    
  • Using the set constructor, which allows you to do several things:

    With no arguments, it creates an empty set:

    >>> foo = set()
    >>> foo
    set()
    

    When passed something it can iterate over, it builds the set from the items in the sequence:

    >>> foo = set('foobarbif')
    >>> foo
    {'a', 'b', 'f', 'i', 'o', 'r'}
    

    When passed a set, this is one way of shallow-copy ing the set:

    >>> foo = set('foobarbif')
    >>> bar = set(foo)
    >>> bar
    {'a', 'b', 'f', 'i', 'o', 'r'}
    

Frozen Set

MUTABILITY: Immutable

The immutable brother of the set type. The advantage to frozensets is that because they are immutable, they can be used as elements in another set, or, as dictionary keys.

Frozen sets can only be created using the frozenset constructor, which operates the same as the set constructor.

Frozensets support all the same common methods as the set type.

Set Operations

All of the set types support a common set of operations which makes working back and forth between them very fluid and easy.

The mutable type supports an additional set of operations (no pun intended) that take advantage of the fact that you can modify its contents without creating a new object.

Common Set Operations

Items in a set can be iterated over. However, the order of items returned is arbitrary. For example:

>>> foo = {'a', 'b', 'c', 99, 'b', 'a', 'z', 4632}
>>> foo
{4632, 99, 'a', 'b', 'c', 'z'}

Which is a different order than that returned when using a loop:

>>> foo = {'a', 'b', 'c', 99, 'b', 'a', 'z', 4632}
>>> for item in foo:
        print(item, end=' ')
c 99 a b z 4632

Sets do not support indexing or slicing / striding using the item access operator []. Attempting to do so will result a TypeError being thrown.

Sets can be compare to each other. Two sets are considered equal, using the == operator, if and only if every element of each set is contained in the other:

>>> foo = {'a', 'b', 'c'}
>>> bar = {'a', 'b', 'c'}
>>> bif = {'a', 'b', 'z'}
>>> baz = {'a', 'b', 'c', 'd'}
>>> foo == bar
True
>>> foo == bif
False
>>> foo == baz
False

Using the other comparison operators, like < and <=, does not behave the same as in other types. This difference is discussed further in Table 12, which enumerates the methods common to all set types, mutable and immutable.

Table 12 Table of Common Set Operations
Operation Description
x in s

Membership testing. Returns True if x is in s.

>>> foo = {'a', 'b', 'c', 'd'}
>>> 'a' in foo
True
x not in s

Membership testing. Returns True if x is not in s.

>>> foo = {'a', 'b', 'c', 'd'}
>>> 5 not in foo
True
len(s)

Returns the number of items in s.

>>> foo = {'a', 'b', 'c', 'd'}
>>> len(foo)
4
s.isdisjoint(t)

Returns True if s has no elements in common with t.

>>> foo = {'a', 'b', 'c', 'd'}
>>> bar = {'a', 'b', 'c', 'd'}
>>> bif = {'w', 'x', 'y', 'z'}
>>> foo.isdisjoint(bar)
False
>>> foo.isdisjoint(bif)
True

s.issubset(t)

s <= t

s < t

Returns True if every element in s is in t.

Use < to test for proper subset (s additionally != t)

>>> foo = {'a', 'b', 'c', 'd'}
>>> bar = {'a', 'b', 'c', 'd', 'e', 'f'}
>>> bif = {'w', 'x', 'y', 'z'}
>>> foo <= bar
True
>>> boo <= bif
False

s.issuperset(t)

s >= t

s > t

Returns True if every element in t is in s.

Use > to test for proper superset (s additional != t)

>>> foo = {'a', 'b', 'c', 'd', 'e', 'f'}
>>> bar = {'a', 'b', 'c', 'd'}
>>> bif = {'w', 'x', 'y', 'z'}
>>> foo >= bar
True
>>> foo >= bif
False

s.union(*t)

s | t | …

Return a new set with the element from s and all others.

>>> foo = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
>>> bar = {15, 20}
>>> bif = {300, 999}
>>> foo | bar | bif
{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 15, 20, 300, 999}

s.intersection(*t)

s & t & …

Return a new set with th elements common to s and all others.

>>> foo = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10                   }
>>> bar = {1,    3,    5,    7,    9,    11, 13, 15, 17, 19}
>>> bif = {1, 2,       5, 6, 7, 8,           13, 15        }
>>> foo & bar & bif
{1, 5, 7}

s.difference(*t)

s - t - …

Return a new set with elements in s that are not in all others.

>>> foo = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10                   }
>>> bar = {1,    3,    5,    7,    9,    11, 13, 15, 17, 19}
>>> bif = {1, 2,       5, 6, 7, 8,           13, 15        }
>>> foo - bar - bif
{4, 10}

s.symmetric_difference(t)

s ^ t

Return a new set with elements in s or t but not both.

>>> foo = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10                   }
>>> bar = {1,    3,    5,    7,    9,    11, 13, 15, 17, 19}
>>> foo ^ bar
{2, 4, 6, 8, 10, 11, 13, 15, 17, 19}

s.copy()

s ^ t

Return a new set that is a shallow copy of s.

>>> foo = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
>>> bar = foo.copy()
>>> bar
{1, 2, 3, 4, 5, 6, 7, 8, 9, 9, 10}

Note

In the table above, t can be any iterable if called on the non-operator versions of union(), intersection(), difference(), symmetric_difference(), issubset() and issuperset(). For example:

>>> {1, 2, 3, 4}.union([6, 8, 10, 12])
{1, 2, 3, 4, 6, 8, 10, 12}

Mutable Set Operations

Mutable set types support additional operations that immutable sets do not. These are shown in Table 13.

Table 13 Table of Mutable Set Operations
Operation Description

s.update(*t)

s |= t | …

Update set s with elements from all others

>>> foo = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10                   }
>>> bar = {1,    3,    5,    7,    9,    11, 13, 15, 17, 19}
>>> bif = {1, 2,       5, 6, 7, 8,           13, 15        }
>>> foo |= bar | bif
>>> foo
{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19}

s.intersection_update(*t)

s &= t & …

Update set s keeping only elements found in it and all others

>>> foo = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10                   }
>>> bar = {1,    3,    5,    7,    9,    11, 13, 15, 17, 19}
>>> bif = {1, 2,       5, 6, 7, 8,           13, 15        }
>>> foo &= bar & bif
>>> foo
{1, 5, 7}

s.difference_update(*t)

s -= t - …

Update set s removing elements found in all others

>>> foo = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10                   }
>>> bar = {1,    3,    5,    7,    9,    11, 13, 15, 17, 19}
>>> bif = {1, 2,       5, 6, 7, 8,           13, 15        }
>>> foo -= bar - bif
>>> foo
{1, 2, 4, 5, 6, 7, 8, 10}

s.symmetric_difference_update(*t)

s ^= t ^ …

Update set s keeping elements found in either set but not both

>>> foo = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10                   }
>>> bar = {1,    3,    5,    7,    9,    11, 13, 15, 17, 19}
>>> bif = {1, 2,       5, 6, 7, 8,           13, 15        }
>>> foo -= bar - bif
>>> foo
{1, 2, 4, 5, 6, 7, 8, 10}

s.add(x)

s ^= t ^ …

Add x to set s

>>> foo = {1, 2, 3, 4}
>>> foo.add(5)
>>> foo
{1, 2, 3, 4, 5}

s.remove(x)

s ^= t ^ …

Remove x from set s.

Raises KeyError if x not found.

>>> foo = {1, 2, 3, 4}
>>> foo.remove(2)
>>> foo
{1, 3, 4}

s.discard(x)

s ^= t ^ …

Remove x from set s.

Won’t raise KeyError if x not found.

>>> foo = {1, 2, 3, 4}
>>> foo.discard(2)
>>> foo
{1, 3, 4}

s.pop()

s ^= t ^ …

Remove an arbitrary element from set s.

Raises KeyError if x not found.

>>> foo = {1, 2, 3, 4}
>>> foo.pop()
>>> foo
1

s.clear()

s ^= t ^ …

Remove all elements from set s.

>>> foo = {1, 2, 3, 4}
>>> foo.clear()
>>> foo
set()

Note

In the table above, t can be any iterable if called on the non-operator versions of update(), intersection_update(), difference_update() and symmetric_difference_update(). For example:

>>> foo = {1, 2, 3, 4}
>>> foo.update([6, 8, 10, 12])
>>> foo
{1, 2, 3, 4, 6, 8, 10, 12}

Try it!

Try the following:

  • Create an empty set.

  • Create a set from the word “basketball”.

  • Using the set:

    s = {2, 8, 9, 11, 15, 19, 32, 29, 30, 45, 46}
    
    • Add the number 32 to the set.
    • Remove the number 19 from the set.
    • Find the length of the set.
  • Determine if ‘dogs’ are pets given the following set:

    pets = {'cats', 'hamsters', 'snakes', 'dogs', 'rock'}