Python
Completed
-
Section 1: Getting Started
-
Section 2: Core Syntax and Data Types
-
Section 3: Collections
-
39: Set Operations: Union, Intersection, Difference
-
Section 4: Control Flow
-
Section 5: Functions
-
Section 6: Turtle Graphics and Early Practice Projects
-
Section 7: Working with Files and I/O
-
Section 8: Regular Expressions
-
Section 9: Object-Oriented Python
-
Section 10: Error Handling
-
Section 11: Modules and Packages
-
Section 12: Iterators, Generators, and Functional Tools
-
Section 13: Decorators and Metaprogramming
-
Section 14: Concurrency and Parallelism
-
Section 15: Working with Dates, Times, and Numbers
-
Section 16: Standard Library Deep Dive I: Data Structures
-
Section 17: Standard Library Deep Dive II: System and Introspection
-
Section 18: Standard Library Deep Dive III: Security and Encoding
-
Section 19: Standard Library Deep Dive IV: Text and Data Utilities
-
Section 20: Networking and Web Basics
-
Section 21: Working with Databases
-
Section 22: Testing and Quality
-
Section 23: Advanced Typing
-
Section 24: Context Managers and Resource Handling
-
Section 25: Text, Unicode, and Binary Data
-
Section 26: More Functional and Iteration Tools
-
Section 27: Data Validation and Configuration
-
Section 28: Working with Images and Media
-
Section 29: Property-Based and Documentation Testing
-
Section 30: Packaging and Deployment
-
Section 31: Performance and Internals
-
Section 32: Design Patterns in Python
-
Section 33: GUI Programming
-
Section 34: Security Basics
-
Section 35: Data Structures and Algorithms
-
Section 36: Practical Projects
-
Section 37: Capstone Projects
-
Section 38: Interview and Algorithm Practice
-
Section 39: Writing Idiomatic Python
38: Sets: Creating and Basic Operations
Imagine you're building a small analytics tool to track unique visitors to a website. You have a log file containing thousands of IP addresses, and you need to figure out exactly how many unique people visited your site. At first glance, this seems like a simple "keep a list" problem.
The O(n) Trap: Checking for Existence in Lists
If you're thinking like a beginner, you might reach for a list. You'd create an empty list, loop through every IP address in your log, and check if the IP is already in your list before adding it. It looks something like this:
unique_ips = []
for ip in log_data:
if ip not in unique_ips:
unique_ips.append(ip)
This works perfectly fine when you have ten or twenty visitors. But here is where we hit a wall as engineers: performance. Every time you call if ip not in unique_ips, Python has to scan the entire list from the beginning to the end to make sure that IP isn't hiding somewhere in the middle. In computer science terms, this is O(n) time complexity. If you have 100,000 logs, you're potentially performing billions of comparisons. Your script will hang, and your CPU will spike, all because you're using a tool designed for ordered sequences to solve a problem of uniqueness.
The Set Shortcut: Hashing for Constant Time
This is exactly why sets exist. A set in Python is essentially a dictionary that only stores keys without any values. Instead of scanning a list, a set uses a hash table. When you check if an item is in a set, Python doesn't "look" through the collection; it computes a hash of the item to jump directly to the memory location where that item would be. This is O(1), or constant time.
The most efficient way to handle our visitor problem is to either cast the entire list to a set or add items as you go:
# The fastest way if you already have the list
unique_ips = set(log_data)
# Or, if you're processing a stream of data
unique_ips = set()
for ip in log_data:
unique_ips.add(ip)
I've seen countless junior devs stick with lists because they want to maintain the order of the elements. If order matters, we can talk about that in a later lesson, but for purely checking uniqueness or membership, the set is your best friend. It's cleaner, it's more intentional, and it's orders of magnitude faster.
Managing Your Collection Without the Overhead
Once you have a set, the operations are intuitive, though they differ slightly from lists. You don't append() to a set—because there is no "end" of a set—you add(). If you try to add an IP that's already there, Python just ignores it. No error, no duplicate, no problem.
You can also remove items using remove() or discard(). Here is a pro tip: use discard() if you aren't 100% sure the item exists. If you call remove() on an item that isn't in the set, Python will raise a KeyError and crash your program. discard(), on the other hand, will fail silently. I generally prefer discard() unless the absence of that item represents a genuine logic error in the application that should crash the program.
visitors = {"192.168.1.1", "10.0.0.1", "172.16.0.1"}
visitors.add("192.168.1.1") # Nothing happens, already exists
visitors.discard("10.0.0.1") # Removed successfully
visitors.discard("8.8.8.8") # Not there, but no error is raised📋 Practical Task
Cleaning the Newsletter Subscriber List
You have been handed a messy list of email addresses from a legacy marketing system. The list contains many duplicates because users signed up multiple times with different forms. Additionally, there are a few "blacklist" emails (like spam@bot.com and test@test.com) that must be removed from the final list before the campaign is sent.
Your Task:
- Create a list called
raw_emailscontaining at least 10 emails, including several duplicates and at least two blacklist emails. - Convert this list into a set to instantly remove all duplicates.
- Use the
discard()method to remove the blacklist emails from your set. - Print the final number of unique, clean subscribers using
len().
There are no comments for now.