Python - Set Comprehension
Set comprehensions follow the same syntactic pattern as list comprehensions but use curly braces instead of square brackets. The basic syntax is `{expression for item in iterable}`, which creates a...
Key Insights
- Set comprehensions provide a concise syntax for creating sets with automatic duplicate removal, offering O(1) average-case membership testing compared to lists’ O(n)
- They support conditional filtering and nested iterations, making them ideal for deduplication, mathematical set operations, and extracting unique elements from complex data structures
- Performance-wise, set comprehensions are faster than using
set()with generator expressions for most use cases, though they consume more memory upfront by creating the entire set immediately
Understanding Set Comprehension Syntax
Set comprehensions follow the same syntactic pattern as list comprehensions but use curly braces instead of square brackets. The basic syntax is {expression for item in iterable}, which creates a set by evaluating the expression for each item.
# Basic set comprehension
numbers = {x for x in range(10)}
print(numbers) # {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
# Automatic deduplication
duplicates = [1, 2, 2, 3, 3, 3, 4, 4, 4, 4]
unique = {x for x in duplicates}
print(unique) # {1, 2, 3, 4}
# With transformation
squares = {x**2 for x in range(6)}
print(squares) # {0, 1, 4, 9, 16, 25}
The key difference from list comprehensions is that sets maintain no order and automatically eliminate duplicates. This makes them particularly useful when you need unique values or fast membership testing.
Conditional Filtering in Set Comprehensions
Add conditional logic using if clauses to filter elements during set creation. This is more efficient than creating a set and filtering afterward.
# Filter even numbers
evens = {x for x in range(20) if x % 2 == 0}
print(evens) # {0, 2, 4, 6, 8, 10, 12, 14, 16, 18}
# Multiple conditions
valid_numbers = {x for x in range(100) if x % 3 == 0 if x % 5 == 0}
print(valid_numbers) # {0, 75, 45, 15, 60, 30, 90}
# String filtering
words = ['apple', 'banana', 'apricot', 'cherry', 'avocado']
a_words = {word.upper() for word in words if word.startswith('a')}
print(a_words) # {'APPLE', 'APRICOT', 'AVOCADO'}
You can also use conditional expressions (ternary operators) within the expression itself:
# Transform based on condition
numbers = {x if x > 0 else -x for x in range(-5, 6)}
print(numbers) # {0, 1, 2, 3, 4, 5}
Nested Iterations and Flattening
Set comprehensions support multiple for clauses, enabling you to iterate over nested structures or create Cartesian products with automatic deduplication.
# Flatten nested lists with deduplication
nested = [[1, 2, 3], [3, 4, 5], [5, 6, 7]]
flattened = {num for sublist in nested for num in sublist}
print(flattened) # {1, 2, 3, 4, 5, 6, 7}
# Cartesian product
colors = ['red', 'blue']
sizes = ['S', 'M', 'L']
combinations = {f"{color}-{size}" for color in colors for size in sizes}
print(combinations) # {'red-S', 'red-M', 'red-L', 'blue-S', 'blue-M', 'blue-L'}
# Extract unique characters from multiple strings
words = ['hello', 'world', 'python']
unique_chars = {char.lower() for word in words for char in word}
print(unique_chars) # {'d', 'e', 'h', 'l', 'n', 'o', 'p', 'r', 't', 'w', 'y'}
Combining nested iterations with conditions:
# Prime factors of multiple numbers
numbers = [12, 18, 24, 30]
all_factors = {
factor
for num in numbers
for factor in range(2, num)
if num % factor == 0
}
print(all_factors) # {2, 3, 4, 5, 6, 9, 10, 12, 15}
Practical Applications in Data Processing
Set comprehensions excel at extracting unique identifiers, deduplicating data, and performing set operations on complex structures.
# Extract unique domains from email addresses
emails = [
'user1@gmail.com',
'user2@yahoo.com',
'user3@gmail.com',
'user4@outlook.com',
'user5@yahoo.com'
]
domains = {email.split('@')[1] for email in emails}
print(domains) # {'gmail.com', 'yahoo.com', 'outlook.com'}
# Find unique tags across blog posts
posts = [
{'title': 'Post 1', 'tags': ['python', 'django', 'web']},
{'title': 'Post 2', 'tags': ['python', 'flask', 'api']},
{'title': 'Post 3', 'tags': ['javascript', 'react', 'web']}
]
all_tags = {tag for post in posts for tag in post['tags']}
print(all_tags) # {'python', 'django', 'web', 'flask', 'api', 'javascript', 'react'}
# Extract unique file extensions
files = ['doc.pdf', 'image.jpg', 'data.csv', 'photo.jpg', 'report.pdf']
extensions = {file.split('.')[-1] for file in files}
print(extensions) # {'pdf', 'jpg', 'csv'}
Working with JSON or API responses:
import json
# Sample API response data
users_data = [
{'id': 1, 'name': 'Alice', 'country': 'USA'},
{'id': 2, 'name': 'Bob', 'country': 'UK'},
{'id': 3, 'name': 'Charlie', 'country': 'USA'},
{'id': 4, 'name': 'Diana', 'country': 'Canada'}
]
# Extract unique countries
countries = {user['country'] for user in users_data}
print(countries) # {'USA', 'UK', 'Canada'}
# Find users with names longer than 5 characters
long_names = {user['name'] for user in users_data if len(user['name']) > 5}
print(long_names) # {'Charlie'}
Performance Considerations
Set comprehensions create the entire set in memory immediately, unlike generator expressions which produce values lazily. Choose based on your use case:
import sys
import time
# Memory comparison
list_comp = [x for x in range(1000000)]
set_comp = {x for x in range(1000000)}
print(f"List size: {sys.getsizeof(list_comp)} bytes") # ~8MB
print(f"Set size: {sys.getsizeof(set_comp)} bytes") # ~32MB
# Speed comparison for membership testing
test_list = [x for x in range(10000)]
test_set = {x for x in range(10000)}
# List lookup (O(n))
start = time.perf_counter()
result = 9999 in test_list
list_time = time.perf_counter() - start
# Set lookup (O(1))
start = time.perf_counter()
result = 9999 in test_set
set_time = time.perf_counter() - start
print(f"List lookup: {list_time:.6f}s")
print(f"Set lookup: {set_time:.6f}s")
print(f"Set is {list_time/set_time:.2f}x faster")
For large datasets where you only need to iterate once, consider generator expressions:
# Set comprehension - creates entire set immediately
unique_squares = {x**2 for x in range(1000000)}
# Generator with set() - more memory efficient for one-time use
unique_squares_gen = set(x**2 for x in range(1000000))
Advanced Patterns with Set Operations
Combine set comprehensions with set operations for powerful data analysis:
# Find common elements between multiple lists
list1 = [1, 2, 3, 4, 5]
list2 = [4, 5, 6, 7, 8]
list3 = [3, 4, 5, 9, 10]
common = {x for x in list1} & {x for x in list2} & {x for x in list3}
print(common) # {4, 5}
# Find elements unique to each dataset
set1 = {x for x in range(10) if x % 2 == 0}
set2 = {x for x in range(10) if x % 3 == 0}
unique_to_set1 = set1 - set2
print(unique_to_set1) # {2, 4, 8}
# Symmetric difference - elements in either set but not both
symmetric = set1 ^ set2
print(symmetric) # {2, 3, 4, 8, 9}
Building lookup sets for validation:
# Valid status codes
valid_statuses = {200, 201, 204, 301, 302, 304, 400, 401, 403, 404, 500}
# Check if response codes are valid
responses = [200, 201, 404, 999, 500, 888]
invalid_codes = {code for code in responses if code not in valid_statuses}
print(invalid_codes) # {888, 999}
# Create allowed IP whitelist
allowed_ips = {f"192.168.1.{i}" for i in range(1, 256)}
incoming_ip = "192.168.1.50"
is_allowed = incoming_ip in allowed_ips # O(1) lookup
Set comprehensions provide a clean, performant way to handle unique collections in Python. Use them when you need automatic deduplication, fast membership testing, or set-based operations on transformed data. For memory-constrained environments or single-pass iterations, consider generator expressions with set() instead.