List Comprehensions & Advanced Collections in Python
Writing clean, concise, and Pythonic code is a key requirement for modern data analysts. This lesson introduces List Comprehensions, Dictionary Comprehensions, Tuples, Sets, and built-in iteration helpers like enumerate() and zip().
1. List Comprehensions: The Pythonic Loop
A list comprehension offers a shorter syntax when you want to create a new list based on the values of an existing iterable.
Traditional For Loop vs. List Comprehension
# Traditional For Loop
salaries = [50000, 65000, 80000, 110000]
bonus_salaries = []
for s in salaries:
bonus_salaries.append(s * 1.10)
# Pythonic List Comprehension
bonus_salaries = [s * 1.10 for s in salaries]
# Output: [55000.0, 71500.0, 88000.0, 121000.0]
Filtering with Conditions in List Comprehensions
You can add an if condition at the end to filter elements:
# Keep only high earners (> 70,000)
high_earners = [s for s in salaries if s > 70000]
# Output: [80000, 110000]
# Conditional transformation (if-else syntax before the for):
labels = ["Senior" if s >= 80000 else "Junior" for s in salaries]
# Output: ['Junior', 'Junior', 'Senior', 'Senior']
2. Dictionary Comprehensions
Similar to list comprehensions, you can construct dictionaries dynamically from lists or existing dictionaries:
employees = ["Alice", "Bob", "Charlie"]
base_salaries = [70000, 85000, 95000]
# Construct dict from paired data:
salary_dict = {employees[i]: base_salaries[i] for i in range(len(employees))}
# Output: {'Alice': 70000, 'Bob': 85000, 'Charlie': 95000}
# Filter dictionary items:
high_paying = {name: sal for name, sal in salary_dict.items() if sal >= 85000}
# Output: {'Bob': 85000, 'Charlie': 95000}
3. Tuples vs. Sets vs. Lists
| Data Structure | Syntax | Ordered? | Mutable? | Duplicates Allowed? | Primary Use Case |
|---|---|---|---|---|---|
| List | [1, 2, 3] |
Yes | Yes | Yes | General-purpose collections of records |
| Tuple | (1, 2, 3) |
Yes | No (Immutable) | Yes | Fixed records, function return values, dict keys |
| Set | {1, 2, 3} |
No | Yes | No (Unique only) | Deduplication, fast membership tests (O(1)) |
Tuple Unpacking & Multiple Returns
# Tuple unpacking
point = (10, 20)
x, y = point
# Function returning multiple values via tuple:
def get_min_max(data):
return min(data), max(data)
low, high = get_min_max([12, 45, 67, 3, 89])
print(f"Min: {low}, Max: {high}") # Min: 3, Max: 89
Set Operations for Data Analysts
jan_customers = {"Alice", "Bob", "Charlie", "Diana"}
feb_customers = {"Charlie", "Diana", "Eve", "Frank"}
# Unique customers across both months (Union):
all_customers = jan_customers | feb_customers
# Returning customers who bought in BOTH months (Intersection):
retained = jan_customers & feb_customers # {'Charlie', 'Diana'}
# Churned customers who bought in Jan but NOT Feb (Difference):
churned = jan_customers - feb_customers # {'Alice', 'Bob'}
4. Built-in Iteration Helpers: enumerate() and zip()
enumerate(): Tracking Index Without Manual Counters
cities = ["New York", "London", "Tokyo", "Paris"]
for idx, city in enumerate(cities, start=1):
print(f"Rank {idx}: {city}")
zip(): Pairing Multiple Sequences Together
names = ["Alice", "Bob", "Charlie"]
scores = [88, 92, 79]
depts = ["Sales", "Engineering", "Marketing"]
for name, score, dept in zip(names, scores, depts):
print(f"{name} ({dept}): {score}/100")