Sets and Frozen sets in Python



Introduction

Sets in Python is an unordered collection with no duplicate elements. Since sets are unordered, we cannot access items using indexes as we do in lists. It is a mutable object that can be modified. But there is another object type called frozen sets that is immutable.

Basic uses of sets include membership testing and eliminating duplicate entries. Moreover, its objects support mathematical operations like union, intersection, difference, and symmetric difference. Python’s set class represents the mathematical notion of a set.

How to create sets in python?

Curly braces or the set() function can be used to create sets and commas to separate its elements.

Example 1:

x = {1,2,3.7,'sets'}
print(x)
print(type(x))

# Output: 
{'sets', 1, 2, 3.7}
<class 'set'>   

Example 2 (creating empty set):

To create an empty set you have to use constructor set(). If you use empty curly braces {} to declare an empty set, It will create an empty dictionary because the dictionary is key-value pairs enclosed inside the curly braces.

empty_set = {} # Wrong way to declare empty set
empty_set1 = set() # Right way to declare empty set
print(f"Data type of empty_set:{type(empty_set)}")
print(f"Data type of empty_set1:{type(empty_set1)}")

# Output
Data type of empty_set:<class 'dict'>
Data type of empty_set1:<class 'set'>

Example 3 (Sets that contain different immutable types of element):

fruits = {'Mango', 'Apple','Banana', 10, 5.5} 
print(fruits)

# Output:
{5.5, 'Apple', 10, 'Mango', 'Banana'}

Example 4 (Sets containing different types of data including mutable data types):

sets = {'Mango', 'Apple','Banana', 10, 5.5, [2, 4.5, 'Python']}
print(sets)

Error message:

Traceback (most recent call last):
File “C:\Users\Dawa Penjor\Desktop\test.py”, line 1, in
sets = {‘Mango’, ‘Apple’,’Banana’, 10, 5.5, [2, 4.5, ‘Python’]}
TypeError: unhashable type: ‘list’

Example 4 runs into an error because sets do not allow mutable data types. We know It can take in different data types but it should be an immutable type. [2, 4.5, ‘Python’] is a mutable list.

Python sets are mutable because we can add and delete elements into them, but they can’t contain mutable items. Like we have seen before, the set can’t contain mutable lists.

Why sets in python are mutable but can’t contain mutable items? Because set internally uses a hash table to store its elements so for that set elements need to be hashable; mutable elements like the list are not hashable.

Note:
Mutable elements are not hashable.
Immutable elements are hashable.



Set does not accept duplicate element

A set is an unordered collection with no duplicate elements. This becomes very useful when we deal with an email address, Identity number, phone number, etc… which is not repeated.

Example:

email_address = {'xyz@gmail.com', 'dawa@gmail.com', 'bht@gmail.com', 'xyz@gmail.com'}
print(email_address)

# Output:
# Duplicate address (xyz@gmail.com) is removed
{'xyz@gmail.com', 'bht@gmail.com', 'dawa@gmail.com'} 

Set does not support indexing

Since the set is an unordered data type, indexing won’t work.

Example:

fruits = {'mango', 'apple', 'Guava'}
print(fruits[1]) # looking for an element at index 1 in fruits

# Error message:
TypeError: 'set' object is not subscriptable
Iteration over a set

We can iterate over a set using a For loop.

Example:

fruits = {'mango', 'apple', 'Guava'}
for i in fruits:
    print(i)

# Output
apple
Guava
mango
Membership check in sets

We can check the element of the set using a membership operator.

Example:

fruits = {'mango', 'apple', 'Guava'}
if 'mango' in fruits:
    print("mango is in fruits list")
else:
    print("fruit not found!")

# Output
mango is in fruits list
Functions that can be used with sets:

The built-in functions such as len(), min(), and max() can be used even in set data type.

Example:

num = {10, 20, 30, 1, 5}
print("Length of the set=",len(num))
print("Minimum value=", min(num))
print("Maximum Value=",max(num))

# Output:
Length of the set= 5
Minimum value= 1
Maximum Value= 30


Sets method:
add()

Adds a new element to a set. This does not affect if the element is already present.

Example:

s = {'2020', 'Python', 'coder'}
s.add('Bhutan')
print(s)

# Output:
{'Bhutan', 'Python', 'coder', '2020'}
clear()

Removes all elements from the set.

Example:

s = {'2020', 'Python', 'coder'}
s.clear()
print(s)

# Output:
set()

copy()

Returns a shallow copy of a set.

Example:

s = {5, 10, 10.5, 'Python'}
s1 = s.copy()
print(s)
print(s1)

# Output:
{'Python', 10, 10.5, 5}
{'Python', 10, 10.5, 5}

difference()

Returns the difference of two or more sets as a new set.

Let’s say that set1 (s1) contains {1, 2, 3, 4, 5} and set2 (s2) contains {4, 5, 6, 7, 8, 9}

Example:

s1 = {1, 2, 3, 4, 5}
s2 = {4, 5, 6, 7, 8, 9}
print(s1.difference(s2))

# Output:
{1, 2, 3} # Elements that are in s1 but not in s2

We can also use the minus (-) operator to display the difference of the set. But when we use the operator, both must be a set.

Example:

# Example 1
s1 = {1, 2, 3, 4, 5}
s2 = {4, 5, 6, 7, 8, 9}
print(s1 - s2)

# output:
{1, 2, 3}

# Example 2:
s1 = {1, 2, 3, 4, 5}
print(s1.difference([4, 5, 6, 7, 8, 9]))
print(s1 - [4, 5, 6, 7, 8, 9]) 

# Output:
{1, 2, 3}
Traceback (most recent call last):
  File "C:\Users\Dawa Penjor\Desktop\test.py", line 3, in <module>
    print(s1 - [4, 5, 6, 7, 8, 9])
TypeError: unsupported operand type(s) for -: 'set' and 'list'

difference_update()

Removes all elements of another set.

Example:

s1 = {1, 2, 3, 4, 5}
s2 = {4, 5, 6, 7, 8, 9}
s1.difference_update(s2)
print(s1) 

# Output:
{1, 2, 3} # All elements of s2 has been removed



symmetric_difference()

Returns the difference of two sets. ie the elements that are in either of the sets, but not in both.

Example:

s1 = {1, 2, 3, 4, 5}
s2 = {4, 5, 6, 7, 8, 9}
print(s1.symmetric_difference(s2))

# Output:
{1, 2, 3, 6, 7, 8, 9}  # Removed 4 and 5 which are in both sets

We can also write using signs. Use ^ to denote symmetric_difference.

Example:

s1 = {1, 2, 3, 4, 5}
s2 = {4, 5, 6, 7, 8, 9}
print(s1 ^ s2)

# Output:
{1, 2, 3, 6, 7, 8, 9}  

symmetric_difference_update()

Update sets with the symmetric difference of itself and another.

Example:

s1 = {1, 2, 3, 4, 5}
s2 = {4, 5, 6, 7, 8, 9}
s1.symmetric_difference_update(s2)
print(s1)

# Output:
{1, 2, 3, 6, 7, 8, 9}
discard()

Removes an element from a set if it is a member. If the element is not a member, do nothing.

Example:

s = {5, 10, 10.5, 'Python'}
s.discard(10)
print(s)

Output:
{'Python', 10.5, 5}

intersection()

This method returns a set that contains the elements that exist in both sets, or all sets if the method is used with more than two sets.

Example:

s1 = {1, 2, 3, 4, 5}
s2 = {4, 5, 6, 7, 8, 9}
print(s1.intersection(s2))

# Output:
{4, 5}

We can also write the intersection of set using &.

Example:

s1 = {1, 2, 3, 4, 5}
s2 = {4, 5, 6, 7, 8, 9}
print(s1 & s2)

# Output:
{4, 5}
intersection_update()

Updates a set with the intersection of itself and another.

Example:

s1 = {1, 2, 3, 4, 5}
s2 = {4, 5, 6, 7, 8, 9}
s1.intersection_update(s2)
print(s1)

# Output:
{4, 5}
isdisjoint()

Returns True if two sets have a null intersection or do not have common elements. If not it returns False.

Example:

s1 = {1, 2, 3, 4, 5}
s2 = {4, 5, 6, 7, 8, 9}
s3 = {10, 11, 12}
print(s1.isdisjoint(s2))
print(s1.isdisjoint(s3))

# Output:
False # Because s1 contains 4 and 5 which is also in s2
True  # Because s1 does not contain any element which is in s3



issubset()

Returns True or False depending on whether another set contains all the elements of other set.

Example:

s1 = {1, 2, 3, 4, 5}
s2 = {4, 5, 6, 7, 8, 9}
s3 = {1, 2, 3, 4, 5, 6, 7, 8, 9}
print(s1.issubset(s2))
print(s1.issubset(s3))

Output:
False  # s2 does not contain all the element of s1. Therefore, s1 is not the subset of s2.
True   # s3 contains all the element of s1. Therefore, s1 is subset of s3.

issuperset()

This method is similar to subset.

Example:

s1 = {1, 2, 3, 4, 5}
s2 = {4, 5, 6, 7, 8, 9}
s3 = {1, 2, 3, 4, 5, 6, 7, 8, 9}
print(s3.issuperset(s1))
print(s2.issuperset(s1))

# Output:
True  # s3 contains all the element of s1
False # s2 doesnot contain all the element of s1

pop()

Removes and returns an arbitrary set element. Raises KeyError if the set is empty.

Example:

s = {5, 10, 10.5, 'Python'}
s.pop()
print(s)

# Output:
{10.5, 5, 'Python'}

remove()

Removes an element from a set; it must be a member. If the element is not a member, raises a KeyError.

Example:

s = {5, 10, 10.5, 'Python'}
s.remove(10)
print(s)

# Output:
{10.5, 5, 'Python'}  # Number 10 is removed

union()

The union of two or more sets is the set of all unique elements present in all the sets. We can also use pipe (|) operator for union.

Example:

s1 = {1, 2, 3, 4, 5}
s2 = {4, 5, 6, 7, 8, 9}
print(s1.union(s2))
print(s1 | s2)    # Union of set using operator

# Output:
{1, 2, 3, 4, 5, 6, 7, 8, 9}
{1, 2, 3, 4, 5, 6, 7, 8, 9} 

update()

Updates a set with the union of itself and others.

Example:

s1 = {1, 2, 3, 4, 5}
s2 = {4, 5, 6, 7, 8, 9}
s1.update(s2)
print(s1)

# Output:
{1, 2, 3, 4, 5, 6, 7, 8, 9}



Frozen sets

Frozenset are immutable sets. They have the same properties as set except they cannot be modified or mutated. Therefore, all methods that don’t modify the set is also available with frozenset.

Frozensets can be used as keys in dictionaries or as element in another set or frozenset.

To create a frozenset we use its constructor.

Example :

fs = frozenset()
print(fs)
print(type(fs))

# Output:
frozenset()
<class 'frozenset'>

Example 2:

fs = frozenset([3, 4, 5.6, 'python'])
print(fs)

# Output:
frozenset({'python', 3, 4, 5.6})