Start learning free

LESSON 259 OF 410 · HASH TABLE

Hash Set in Python: How to Use the set Type

Lesson Read the full explanation

Hash Sets are collections of unique items i.e no element can be repeated.

Hash Sets were designed to give us a way of adding and looking for unique values in a collection in a quick manner.

The values in a Hash Set can be either simple primitives like strings or integers as well as more complex object types like object literals or arrays.

In Python, the Hash Set is implemented as the set object.


Creation:

You can create a new empty set by using set():

emptySet = set()

Creating an empty set takes O(1) time.


Constructing from iterable:

The set constructor also accepts an optional iterable object. If you pass an iterable object to the set constructor, all the unique elements from the object will be added to the new set:

elements = [1, '2', 'apple', 1]
mySet = set(elements)

print(mySet) # {1, '2', 'apple'}

This takes O(n) time, where n is the number of elements in the iterable object.


Initialization

Sets containing values can also be initialized by using curly braces:

dataEngineer = {'Python', 'Java', 'Scala', 'Git', 'SQL', 'Hadoop'}

Keep in mind that curly braces can only be used to initialize a set containing values. Empty curly braces ({}) create an empty dictionary, not a set.


Adding elements:

To add an element to the set, you use the add() method:

mySet = {'a', 'b', 'c'}

# Adding new element:
mySet.add('d')

# Adding existing element:
mySet.add('a') # nothing happens

print(mySet) # {'a', 'b', 'c', 'd'}

The set first checks if that element already exists and if so, it does nothing and also doesn't raise an error.

Adding an element to a set takes O(1) time.


Checking if a value exists:

To check if a set has a specific element, you use the in operator:

mySet = {'a', 'b', 'c'}

print('a' in mySet) # True

exist = 'z' in mySet
print(exist) # False

Checking if a value exists in a set takes O(1) time.


Removing elements:

To delete a specified element from a set, you use the remove() method:

mySet = {'a', 'b', 'c', 'd'}

# Deleting elements:
mySet.remove('a')

# Deleting a non-existent element:
mySet.remove('z') # raises KeyError exception

print(mySet) # {'b', 'c', 'd'}

The set first checks if that key exists and if not, it raises a KeyError. If you want a function that leaves a set unchanged if the element is not present, you can use discard():

mySet = {'a', 'b', 'c', 'd'}

# Discarding existent element:
mySet.discard('a') # removes 'a'

# Discarding non-existent element:
mySet.discard('z') # nothing happens

print(mySet) # {'b', 'c', 'd'}

Removing an element from a set takes O(1) time.


Iterating over the Set values:

If we want to iterate over values of the set, we can use the for loop along with the in operator:

mySet = {'b', 'c', 'c', 'd'}

for val in mySet:
    print(val)

# This will print the following:
# b
# d
# c

Notice the order is not the same as we initiated. set keeps the data in random order

Iterating over a set takes O(n) time.


Space Complexity

A set uses O(n) space, where n is the number of elements existing in the set.


Assignment
Follow the Coding Tutorial and let's play with some Hash Sets.


Hint
Look at the examples above if you get stuck.


STEP 1 OF 6
    Ctrl + Enter to check

    PYTHON · HASH TABLE

    Hash Set in Python, explained

    What a hash set is, and what it is called in Python

    A hash set is a collection of unique values with very fast insertion and lookup. If you add a value that is already inside, nothing changes, so no value appears twice. Python has no class called HashSet: its built-in set type is a hash set. When people search for a "hashset in Python", the answer is set.

    It is fast because it stores each value at a position computed from the value's hash. To test whether a value is present, Python computes the hash and looks at that position instead of scanning every element. Adding, removing and checking take O(1) time on average, while checking whether a value is in a list takes O(n).

    Use a set when you need to remove duplicates, check membership quickly, or compare groups of values. A set does not keep an order and cannot be indexed, so my_set[0] is an error.

    Creating a set

    An empty set

    Call set() with no arguments. Empty curly braces do not work: {} creates an empty dictionary.

    emptySet = set()
    print(type(emptySet))  # <class 'set'>
    print(type({}))        # <class 'dict'>
    

    From a list or another iterable

    Pass any iterable to set() and the duplicates disappear. This takes O(n) time for n elements:

    elements = [1, '2', 'apple', 1]
    mySet = set(elements)
    print(len(mySet))  # 3
    print(set("hello") == {'h', 'e', 'l', 'o'})  # True
    

    With curly braces

    When you already know the values, list them in braces:

    dataEngineer = {'Python', 'Java', 'Scala', 'Git', 'SQL', 'Hadoop'}
    

    Adding, checking and removing

    mySet = {'a', 'b', 'c'}
    
    mySet.add('d')   # added
    mySet.add('a')   # already there, nothing happens
    
    print('a' in mySet)  # True
    print('z' in mySet)  # False
    print(len(mySet))    # 4
    
    • add(x) inserts x if it is missing and does nothing, without an error, if it is already there. To add several values at once, use update([...]).
    • x in s is the membership test, and x not in s is its opposite.
    • remove(x) deletes x and raises KeyError when it is missing.
    • discard(x) deletes x and does nothing when it is missing. It is the safer choice when you don't know whether the value is there.
    mySet = {'a', 'b', 'c', 'd'}
    
    mySet.discard('a')   # removes 'a'
    mySet.discard('z')   # nothing happens
    mySet.remove('z')    # KeyError: 'z'
    

    Looping over a set

    A for loop visits each value once, in no order you can rely on. For small integers the order often looks sorted, and for strings it can change from one run of the program to the next. If you need a stable order, loop over sorted(mySet).

    mySet = {'b', 'c', 'c', 'd'}
    
    for val in mySet:
        print(val)
    
    print(sorted(mySet))  # ['b', 'c', 'd']
    

    The loop prints b, c and d in some order, and c only once.

    What can go in a set

    Every element of a set must be hashable. Numbers, strings, booleans and tuples of such values qualify. Lists, dictionaries and other sets do not, because they can change after they are added:

    print({(1, 2), (1, 2)})   # {(1, 2)}
    {[1, 2]}                  # TypeError: unhashable type: 'list'
    

    To put a set inside another set, use a frozenset, an immutable version: frozenset([1, 2]).

    The lesson's exercise, step by step

    1. Make a list with a duplicate. fruitsArray holds 'apples', 'bananas' and 'apples'. A list keeps all three.
    2. Convert it to a set. fruits = set(fruitsArray) keeps two values, because the second 'apples' is a duplicate.
    3. Add a new value. fruits.add('oranges') grows the set to three values.
    4. Check for a value. 'apples' in fruits is true, so the program prints We have apples.
    5. Remove a value. fruits.discard('bananas') leaves 'apples' and 'oranges'.
    6. Print every value with a for loop over fruits, using the loop variable fruit.
    fruitsArray = ['apples', 'bananas', 'apples']
    
    fruits = set(fruitsArray)
    
    fruits.add('oranges')
    
    if 'apples' in fruits:
        print('We have apples')
    
    fruits.discard('bananas')
    
    for fruit in fruits:
        print(fruit)
    

    The program prints We have apples, then apples and oranges in either order.

    Set operations

    Sets also support the maths of collections, which makes them handy for comparing data:

    a = {1, 2, 3}
    b = {3, 4}
    
    print(a | b)   # {1, 2, 3, 4}  union
    print(a & b)   # {3}           intersection
    print(a - b)   # {1, 2}        in a but not in b
    print(a ^ b)   # {1, 2, 4}     in exactly one of them
    

    Complexity

    • Create an empty set: O(1).
    • Build from an iterable of n items: O(n).
    • Add, remove, discard and in: O(1) on average. In the rare worst case, many values with the same hash, they degrade to O(n).
    • Loop over all values: O(n).
    • Space: O(n) for n values.

    Common mistakes

    • Using {} for an empty set. It creates a dictionary. Use set().
    • Expecting an order or an index. fruits[0] raises TypeError, and the loop order is not part of the contract.
    • Using remove on a value that may be missing. It raises KeyError. Use discard.
    • Adding a list. s.add([1, 2]) fails with unhashable type: 'list'. Convert it to a tuple first.
    • Expecting True, 1 and 1.0 to be different. They are equal and have the same hash, so len({1, 1.0, True}) is 1.

    Key takeaways

    • In Python, set is the hash set: unique values, fast membership tests.
    • Create one with set(), set(iterable) or {...} with values; {} is a dictionary.
    • Use add, in, discard and a for loop for the basics.
    • Elements must be hashable, and the iteration order is not guaranteed.
    Keep going with PythonAbout 340 step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free