0%

72- Advanced Sets

Master set operations for complex data analysis. Supersets, subsets, disjoint checks, and advanced set methods. Go beyond basic uniqueness.

You know sets: unordered collections of unique items. You can add, remove, and check membership. But sets can do much more.
Sets are mathematical objects. They support operations like union, intersection, difference, and symmetric difference. You can check if one set is a subset of another. You can create frozensets (immutable sets) for use as dictionary keys. You can perform complex set algebra.
This lesson explores advanced set operations. You will learn to test subsets and supersets, find disjoint sets, use set comprehensions, work with frozensets, and apply set operations to real-world problems like finding common interests, analyzing user permissions, and deduplication pipelines.

🕯️ Magic Note

Sets are implemented using hash tables, making membership tests O(1) on average. This makes sets incredibly fast for checks like if item in set:, even for very large sets (millions of items). The same operation on a list is O(n).

Subset and Superset Tests
Check if all elements of one set are contained in another.

Python

A = {1, 2, 3, 4, 5}

B = {1, 2, 3}

C = {1, 2, 3, 4, 5, 6}

D = {6, 7, 8}

# issubset() – all elements of first are in second

print(B.issubset(A)) # True (B ⊆ A)

print(B.issubset(C)) # True

print(A.issubset(B)) # False

print(D.issubset(A)) # False

# issuperset() – all elements of second are in first

print(A.issuperset(B)) # True (A ⊇ B)

print(C.issuperset(A)) # True

print(B.issuperset(A)) # False

# Subset with operators (<= and <)

print(B <= A) # True (subset, could be equal)

print(B < A) # True (proper subset, cannot be equal)

print(A <= A) # True (subset includes equality)

print(A < A) # False (proper subset does not include equality)

# Superset with operators (>= and >)

print(A >= B) # True

print(A > B) # True

💡 Use <= and >= for subset/superset checks when you want to allow equality. Use < and > for proper subset/superset (strictly smaller or larger).
Disjoint Sets
Check if two sets have no elements in common.

Python

A = {1, 2, 3, 4, 5}

B = {6, 7, 8}

C = {4, 5, 6, 7}

# isdisjoint() returns True if no common elements

print(A.isdisjoint(B)) # True (no overlap)

print(A.isdisjoint(C)) # False (share 4 and 5)

print(B.isdisjoint(C)) # False (share 6 and 7)

# Equivalent to intersection being empty

print(len(A & B) == 0) # True

print(A & B == set()) # True

🕯️ Magic Note

The isdisjoint() method is more efficient than checking intersection because it stops as soon as any common element is found, without creating a new set.

Set Operations in Place
Modify a set in place using update methods.

Python

A = {1, 2, 3}

B = {3, 4, 5}

# In-place union (adds elements from B to A)

A.update(B)

print(A) # {1, 2, 3, 4, 5}

A = {1, 2, 3, 4, 5}

# In-place intersection (keeps only elements in both)

A.intersection_update(B)

print(A) # {3, 4, 5}

A = {1, 2, 3, 4, 5}

# In-place difference (removes elements in B)

A.difference_update(B)

print(A) # {1, 2}

A = {1, 2, 3, 4, 5}

# In-place symmetric difference (elements in either but not both)

A.symmetric_difference_update(B)

print(A) # {1, 2} (from A) union {4,5}? Wait: symmetric = {1,2} ∪ {4,5} = {1,2,4,5}

# Let me recalc: A={1,2,3,4,5}, B={3,4,5}, symmetric = {1,2} (only in A) plus empty from B = {1,2}

💡 In-place methods (update(), intersection_update(), etc.) modify the original set and return None. Use them to save memory when you do not need the original set.
Frozensets (Immutable Sets)
Frozensets are immutable versions of sets. They can be used as dictionary keys.

Python

# Creating frozensets

fs1 = frozenset([1, 2, 3, 3, 2]) # frozenset({1, 2, 3})

fs2 = frozenset({3, 4, 5})

print(fs1) # frozenset({1, 2, 3})

print(type(fs1)) # <class ‘frozenset’>

# Frozensets support set operations

print(fs1 | fs2) # frozenset({1, 2, 3, 4, 5})

print(fs1 & fs2) # frozenset({3})

print(fs1 – fs2) # frozenset({1, 2})

# Cannot modify frozensets

# fs1.add(4) # AttributeError: ‘frozenset’ object has no attribute ‘add’

# Frozensets as dictionary keys (regular sets cannot be keys)

dict_with_frozenset = {

frozenset([1, 2]): “pair”,

frozenset([1, 2, 3]): “triple”,

frozenset([1, 2, 3, 4]): “quad”

}

print(dict_with_frozenset[frozenset([1, 2])]) # ‘pair’

# Convert set to frozenset

s = {1, 2, 3}

fs = frozenset(s)

🕯️ Magic Note

Frozensets are hashable because they are immutable. This makes them useful as dictionary keys or elements of other sets. Regular sets are unhashable and cannot be used in these contexts.

Set Comprehensions with Conditions
Create sets using comprehensions with complex conditions.

Python

# Basic set comprehension

squares = {x**2 for x in range(10)}

print(squares) # {0, 1, 4, 9, 16, 25, 36, 49, 64, 81}

# Set comprehension with filter

even_squares = {x**2 for x in range(20) if x % 2 == 0}

print(even_squares) # {0, 4, 16, 36, 64, 100, 144, 196, 256, 324}

# Set comprehension from another iterable

text = “hello world”

unique_chars = {char for char in text if char != ” “}

print(unique_chars) # {‘h’, ‘e’, ‘l’, ‘o’, ‘w’, ‘r’, ‘d’}

# Nested set comprehension (flattening)

matrix = [[1, 2, 3], [4, 2, 6], [7, 8, 9]]

unique_values = {val for row in matrix for val in row}

print(unique_values) # {1, 2, 3, 4, 6, 7, 8, 9}

# Set comprehension with conditional expression

numbers = [1, 2, 3, 4, 5]

labels = {“even” if x % 2 == 0 else “odd” for x in numbers}

print(labels) # {‘odd’, ‘even’}

Practical Example: Finding Common Interests
Use set operations to find overlapping interests between users.

Python

# User interests as sets

ali = {“Python”, “Coffee”, “Magic”, “Books”, “Music”}

sara = {“Python”, “Coffee”, “Travel”, “Photography”, “Music”}

reza = {“Java”, “Coffee”, “Sports”, “Movies”, “Games”}

# Common interests between Ali and Sara

common_ali_sara = ali & sara

print(f”Ali and Sara share: {common_ali_sara}”)

# Interests unique to Ali (not in any other set)

unique_ali = ali – (sara | reza)

print(f”Unique to Ali: {unique_ali}”)

# Interests that only one person has

all_interests = ali | sara | reza

def exclusive_interests(*sets):

“””Return interests that appear in exactly one set.”””

result = set()

all_items = set().union(*sets)

for item in all_items:

count = sum(1 for s in sets if item in s)

if count == 1:

result.add(item)

return result

exclusive = exclusive_interests(ali, sara, reza)

print(f”Exclusive interests: {exclusive}”)

# Interests shared by at least two people

pairwise_common = (ali & sara) | (ali & reza) | (sara & reza)

print(f”Interests shared by at least two: {pairwise_common}”)

# Suggest new interests based on what similar users like

def suggest_interests(user, similar_user, user_interests, all_interests):

“””Suggest interests from similar user that the current user does not have.”””

return similar_user – user

suggestions = suggest_interests(ali, sara, ali, all_interests)

print(f”Suggestions for Ali based on Sara: {suggestions}”)

Practical Example: Data Deduplication Pipeline
Use sets to remove duplicates from large datasets efficiently.

Python

import csv

from pathlib import Path

def deduplicate_csv(input_file, output_file, key_field=”email”):

“””Remove duplicate rows from a CSV file based on a key field.”””

seen = set()

unique_rows = []

with open(input_file, “r”, encoding=”utf-8″) as f:

reader = csv.DictReader(f)

fieldnames = reader.fieldnames

for row in reader:

key = row.get(key_field)

if key and key not in seen:

seen.add(key)

unique_rows.append(row)

with open(output_file, “w”, encoding=”utf-8″, newline=””) as f:

writer = csv.DictWriter(f, fieldnames=fieldnames)

writer.writeheader()

writer.writerows(unique_rows)

print(f”Deduplicated {len(seen)} unique records out of {len(seen) + (len(unique_rows) – len(seen))} total”)

# Example: Find duplicate files by content hash

import hashlib

def find_duplicate_files(directory):

“””Find duplicate files in a directory using MD5 hashes.”””

seen_hashes = set()

duplicates = []

for file_path in Path(directory).rglob(“*”):

if file_path.is_file():

with open(file_path, “rb”) as f:

file_hash = hashlib.md5(f.read()).hexdigest()

if file_hash in seen_hashes:

duplicates.append(file_path)

else:

seen_hashes.add(file_hash)

return duplicates

Working with Large Sets: Memory and Performance
Sets are fast but memory-intensive. Here are optimization tips.

Python

# Sets use more memory than lists (overhead for hash table)

import sys

lst = list(range(1000000))

st = set(range(1000000))

print(f”List memory: {sys.getsizeof(lst) / 1024 / 1024:.2f} MB”)

print(f”Set memory: {sys.getsizeof(st) / 1024 / 1024:.2f} MB”)

# If you only need to check membership, use set

# If you need order and allow duplicates, use list

# If you need order but no duplicates, use dict.fromkeys()

🕯️ Magic Note

Sets are optimized for speed, not memory. The hash table overhead can be 2-3x the size of the data. For very large sets, consider using bloom filters (third-party library) for probabilistic membership tests with much lower memory usage.

Common Mistakes with Advanced Sets
  • Expecting sets to preserve order (they do not in Python versions before 3.7; even after 3.7, order is insertion order but not guaranteed for all operations)
  • Using mutable elements in sets (lists, dicts, other sets)
  • Forgetting that update() modifies in place and returns None
  • Using regular sets as dictionary keys (use frozenset)
  • Assuming isdisjoint() creates an intersection (it does not, it stops early)
Check Your Understanding
  • Write a function that checks if one set is a subset of another without using built-in methods.
  • What is the difference between issubset() and the <= operator?
  • Create a frozenset and use it as a key in a dictionary.
  • Write a set comprehension that creates a set of vowels from a given string.
  • How do you find the elements that are in set A but not in set B or set C?
  • When would you use intersection_update() instead of intersection()?

⚡ Whisper

Sets are the mathematicians’ gift to programmers. They speak the language of Venn diagrams. Union, intersection, difference, subset. With sets, you ask: “What do these groups share?” The answer comes instantly. “What is unique to this group?” The difference appears. “Is this group entirely contained in that one?” The subset test decides. Sets are fast. They are exact. They eliminate duplicates without thought. They find overlaps without loops. For permissions, tags, categories, interests, deduplication, set operations are unmatched. Learn the operators. Master the methods. Then apply them to your data. The relationships between sets will reveal insights you never saw. The sets are waiting. Their logic is clear. Use it.

Related posts