Python online course

Python Sets: Unique, Unordered Collections

Learn how Python sets store unique values, remove duplicates, test membership, change contents, and perform union, intersection, difference, and other set operations.

A set is a Python collection designed to store distinct, or unique, values. Sets are useful when duplicate entries should be eliminated or when your main question is whether a value exists in a collection.

Unlike a list, which is a sequence with positions, a set is primarily used for membership tests. A membership test checks whether a value exists, usually with in or not in.

Creating a Set

A non-empty set can be written with curly braces. This syntax is called a set literal.

programming_languages = {'Python', 'JavaScript', 'Go'}
print(programming_languages)

The displayed order is not meaningful. Sets are unordered: they do not provide a stable positional order that your program should depend on.

An empty set must be created with set():

names = set()
print(names)  # set()

Although curly braces create a non-empty set, {} creates an empty dictionary:

empty_dictionary = {}
empty_set = set()

You can also create a set from any iterable, such as a list, string, tuple, or another set:

course_tags = ['python', 'beginner', 'python', 'collections']
unique_tags = set(course_tags)

print(unique_tags)
print(len(unique_tags))

How Sets Remove Duplicates

When a set is created, repeated equal values are stored only once. The duplicates are discarded during creation.

scores = {10, 20, 10, 30, 20}
print(scores)       # {10, 20, 30} in some display order
print(len(scores))  # 3

The same rule applies when adding values later. Calling add() with a value already present does not create a second copy.

attendees = {'Maya', 'Noah'}
attendees.add('Maya')

print(attendees)  # Maya still appears only once

Duplicate removal is based on equality and hashing. A value is hashable when it can provide a stable hash value and can therefore be used as a set element or dictionary key.

Sets Are Unordered

A set does not preserve a defined item position or insertion order for programming purposes. Its printed or iterated order can differ between runs, Python versions, or environments.

colors = {'red', 'green', 'blue'}
print(colors)  # Do not rely on the displayed order

Sets cannot be indexed or sliced:

colors = {'red', 'green', 'blue'}
# colors[0]       # TypeError
# colors[0:2]     # TypeError

Use a membership test or loop when you need to work with set values. If you need a predictable ordered view, convert the set to a sorted list:

ordered_colors = sorted(colors)
print(ordered_colors)

Mutable Sets and Hashable Elements

A normal set is a mutable container. You can add and remove elements after creating it. However, every direct element inside the set must be hashable.

Immutable values such as strings, integers, booleans, and tuples containing hashable values can normally be set elements. Mutable values such as lists and dictionaries cannot be direct elements:

valid_values = {1, 'Python', (10, 20)}

# invalid_values = {[1, 2], {'language': 'Python'}}
# TypeError: unhashable type

Use a tuple when fixed sequence data should be an element, or a frozenset when nested set-like data is appropriate:

coordinates = {(10, 20), (30, 40)}
permissions = {frozenset({'read', 'write'})}

A frozenset is an immutable set variant. It cannot be changed after creation and can itself be used as a set element or dictionary key.

Featuresetfrozenset
Can add or remove elementsYesNo
Can be used as a set elementNoYes
Can be used as a dictionary keyNoYes
Creation syntax{1, 2} or set(iterable)frozenset(iterable)

Basic Set Operations

Adding Values

Use add() to add one element. If the element is already present, the set remains unchanged.

names = {'Maria', 'Lucy'}
names.add('Nina')
names.add('Maria')
print(names)

Use update() to add several elements from another iterable:

languages = {'Python'}
languages.update(['JavaScript', 'Go', 'Python'])
print(languages)

Removing Values

remove(value) removes a known value, but raises KeyError if that value is absent. discard(value) removes a value if present and does nothing if it is absent.

languages = {'Python', 'JavaScript', 'Go'}
languages.remove('Go')
languages.discard('Ruby')  # Safe when Ruby is absent

# languages.remove('Ruby')  # KeyError

Use pop() to remove and return an arbitrary element. Because sets are unordered, you cannot predict which element it returns. Calling it on an empty set raises KeyError.

languages = {'Python', 'JavaScript'}
removed_language = languages.pop()
print(removed_language)

Use clear() to remove every element:

languages.clear()
print(languages)  # set()

Membership and Size

Use in and not in to test membership. Use len() to count the unique elements.

approved_usernames = {'maya', 'noah', 'li'}
username = 'maya'

if username in approved_usernames:
    print('Access approved')

if 'admin' not in approved_usernames:
    print('Admin is not approved')

print(len(approved_usernames))  # 3
OperationMethod or operatorResultImportant behavior
Add one elementvalues.add(item)Changes the setExisting duplicates are ignored
Add multiple elementsvalues.update(iterable)Changes the setAdds each distinct element from the iterable
Safe removalvalues.discard(item)Changes the set if presentNo error when absent
Strict removalvalues.remove(item)Changes the setRaises KeyError when absent
Membership checkitem in valuesTrue or FalseUseful for presence checks
Unionvalues.union(other) or values | otherAll distinct elementsElements from either set
Intersectionvalues.intersection(other) or values & otherShared elementsElements in both sets
Differencevalues.difference(other) or values - otherElements only in the first setOrder matters between the operands
Symmetric differencevalues.symmetric_difference(other) or values ^ otherElements in exactly one setShared elements are excluded
Count elementslen(values)Number of unique elementsDuplicates are never counted twice

Set Algebra

Set algebra compares collections of values. The named methods make the operation explicit, while operators provide concise notation.

coding_club = {'Maya', 'Noah', 'Li'}
robotics_club = {'Noah', 'Ava', 'Li'}

all_members = coding_club | robotics_club
shared_members = coding_club & robotics_club
coding_only = coding_club - robotics_club
exactly_one_club = coding_club ^ robotics_club

print(all_members)
print(shared_members)
print(coding_only)
print(exactly_one_club)
  • Union: values present in either set. Use union() or |.
  • Intersection: values shared by both sets. Use intersection() or &.
  • Difference: values in one set but absent from another. Use difference() or -.
  • Symmetric difference: values present in exactly one of two sets, not both. Use symmetric_difference() or ^.

For example, coding_club - robotics_club means members only in the coding club. Reversing the operands produces members only in the robotics club.

Choosing a Set, List, or Dictionary

Collection typeStoresDuplicates allowedOrder or positionIndexingTypical use
setDistinct hashable valuesNoNo stable positional orderNoUniqueness, membership tests, set algebra
listValues in a sequenceYesPreserves sequence orderYesOrdered data, repeated values, positional access
dictionaryUnique keys mapped to valuesKeys must be uniquePreserves insertion orderNo numeric indexingLooking up a value by a named key

Choose a set when uniqueness and efficient membership checks matter. Choose a list when order, indexing, or duplicate counts matter. Choose a dictionary when each key needs an associated value.

For example, a list can represent every vote, including repeated votes, while a set can represent the distinct usernames that submitted votes. A dictionary can map each username to that user's vote count.

Common Problems and Fixes

  • {} is not an empty set: use set(), because {} is an empty dictionary.
  • Indexing fails: sets have no positional indexing. Use value in values, iterate over the set, or use sorted(values) for an ordered view.
  • Printed order changes: do not depend on set display or iteration order. Sort a copy when predictable presentation is required.
  • TypeError when adding a list or dictionary: those mutable objects are unhashable. Use a tuple for fixed sequence data or a frozenset for nested set-like data.
  • remove() raises KeyError: use discard() when absence is acceptable, or test membership before calling remove().
  • Confusing element immutability with container immutability: elements must be hashable, but a normal set can still change with add(), update(), and removal methods. Use frozenset when the collection itself must not change.

Quick Practice Example

names = set(['Maria', 'Lucy', 'Maria', 'Tanya'])
print(names)
print(len(names))

names.add('Nina')
names.update(['Lucy', 'Omar'])
names.discard('Lucy')

print('Maria' in names)
print('Lucy' not in names)
print(names)

This example converts a list to a set, removes the repeated 'Maria', adds one value, adds several values, safely removes a value, and performs membership tests.

Summary

  • A set stores distinct hashable elements.
  • Duplicate equal values are discarded during creation and later additions.
  • Sets are unordered and cannot be indexed or sliced.
  • Normal sets are mutable; frozenset is immutable.
  • Use in, not in, and len() for common membership and size operations.
  • Use union, intersection, difference, and symmetric difference to compare groups of values.
  • Use lists for ordered sequences, sets for uniqueness, and dictionaries for key-value mappings.

For related collection concepts, review Python lists, modifying lists, and looping through dictionaries. You can also explore the Python online course.