python-by-example/09_advanced_python/01_list_comprehensions.py
2025-12-30 08:50:00 +02:00

305 lines
9.6 KiB
Python

"""
================================================================================
File: 01_list_comprehensions.py
Topic: List Comprehensions and Other Comprehensions
================================================================================
This file demonstrates comprehensions in Python - a concise and powerful way
to create lists, dictionaries, sets, and generators. Comprehensions are more
readable and often faster than traditional loops.
Key Concepts:
- List comprehensions
- Dictionary comprehensions
- Set comprehensions
- Generator expressions
- Nested comprehensions
- When to use comprehensions
================================================================================
"""
# -----------------------------------------------------------------------------
# 1. Basic List Comprehension
# -----------------------------------------------------------------------------
# [expression for item in iterable]
print("--- Basic List Comprehension ---")
# Traditional way
squares_loop = []
for x in range(1, 6):
squares_loop.append(x ** 2)
print(f"Loop method: {squares_loop}")
# List comprehension way
squares_comp = [x ** 2 for x in range(1, 6)]
print(f"Comprehension: {squares_comp}")
# More examples
numbers = [1, 2, 3, 4, 5]
doubled = [n * 2 for n in numbers]
strings = [str(n) for n in numbers]
print(f"\nOriginal: {numbers}")
print(f"Doubled: {doubled}")
print(f"As strings: {strings}")
# -----------------------------------------------------------------------------
# 2. List Comprehension with Condition
# -----------------------------------------------------------------------------
# [expression for item in iterable if condition]
print("\n--- Comprehension with Condition ---")
# Get only even numbers
numbers = range(1, 21)
evens = [n for n in numbers if n % 2 == 0]
print(f"Even numbers: {evens}")
# Filter and transform
words = ["hello", "world", "python", "AI", "ml"]
long_upper = [w.upper() for w in words if len(w) > 3]
print(f"Long words (uppercase): {long_upper}")
# Multiple conditions (AND)
numbers = range(1, 51)
divisible_by_3_and_5 = [n for n in numbers if n % 3 == 0 and n % 5 == 0]
print(f"Divisible by 3 and 5: {divisible_by_3_and_5}")
# -----------------------------------------------------------------------------
# 3. Conditional Expression in Comprehension
# -----------------------------------------------------------------------------
# [expr1 if condition else expr2 for item in iterable]
print("\n--- Conditional Expression ---")
# Replace negatives with zero
numbers = [-3, -1, 0, 2, 5, -4, 8]
non_negative = [n if n >= 0 else 0 for n in numbers]
print(f"Original: {numbers}")
print(f"Non-negative: {non_negative}")
# Categorize numbers
categorized = ["even" if n % 2 == 0 else "odd" for n in range(1, 6)]
print(f"Categories: {categorized}")
# Pass/fail based on score
scores = [85, 42, 91, 78, 55]
results = ["Pass" if s >= 60 else "Fail" for s in scores]
print(f"Scores: {scores}")
print(f"Results: {results}")
# -----------------------------------------------------------------------------
# 4. Nested Loops in Comprehension
# -----------------------------------------------------------------------------
print("\n--- Nested Loops ---")
# Flatten a 2D list
matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
flat = [num for row in matrix for num in row]
print(f"Matrix: {matrix}")
print(f"Flattened: {flat}")
# All combinations
colors = ["red", "green"]
sizes = ["S", "M", "L"]
combinations = [(color, size) for color in colors for size in sizes]
print(f"\nCombinations: {combinations}")
# Multiplication table
table = [[i * j for j in range(1, 4)] for i in range(1, 4)]
print("\nMultiplication table:")
for row in table:
print(f" {row}")
# -----------------------------------------------------------------------------
# 5. Dictionary Comprehensions
# -----------------------------------------------------------------------------
# {key: value for item in iterable}
print("\n--- Dictionary Comprehensions ---")
# Square numbers dictionary
squares_dict = {x: x ** 2 for x in range(1, 6)}
print(f"Squares dict: {squares_dict}")
# From two lists
keys = ["name", "age", "city"]
values = ["Alice", 25, "NYC"]
person = {k: v for k, v in zip(keys, values)}
print(f"Person dict: {person}")
# Swap keys and values
original = {"a": 1, "b": 2, "c": 3}
swapped = {v: k for k, v in original.items()}
print(f"Original: {original}")
print(f"Swapped: {swapped}")
# Filter dictionary
scores = {"Alice": 85, "Bob": 42, "Charlie": 91, "Dave": 55}
passing = {name: score for name, score in scores.items() if score >= 60}
print(f"\nPasssing students: {passing}")
# Transform dictionary
prices = {"apple": 1.5, "banana": 0.75, "cherry": 2.0}
taxed = {item: price * 1.1 for item, price in prices.items()}
print(f"With tax: {taxed}")
# -----------------------------------------------------------------------------
# 6. Set Comprehensions
# -----------------------------------------------------------------------------
# {expression for item in iterable}
print("\n--- Set Comprehensions ---")
# Unique squares
numbers = [1, 2, 2, 3, 3, 3, 4, 4, 4, 4]
unique_squares = {x ** 2 for x in numbers}
print(f"Numbers: {numbers}")
print(f"Unique squares: {unique_squares}")
# Unique first letters
words = ["apple", "banana", "apricot", "blueberry", "cherry"]
first_letters = {w[0] for w in words}
print(f"First letters: {first_letters}")
# Get unique word lengths
sentences = "the quick brown fox jumps over the lazy dog"
word_lengths = {len(word) for word in sentences.split()}
print(f"Unique word lengths: {word_lengths}")
# -----------------------------------------------------------------------------
# 7. Generator Expressions
# -----------------------------------------------------------------------------
# (expression for item in iterable) - lazy evaluation!
print("\n--- Generator Expressions ---")
# Generator expression (note the parentheses)
squares_gen = (x ** 2 for x in range(1, 6))
print(f"Generator object: {squares_gen}")
print(f"As list: {list(squares_gen)}")
# Memory efficient for large data
# List: creates all values immediately
# Generator: creates values on demand
# Sum of squares (generator is more memory efficient)
total = sum(x ** 2 for x in range(1, 1001))
print(f"Sum of squares 1-1000: {total}")
# Check if any/all
numbers = [1, 3, 5, 7, 9]
any_even = any(n % 2 == 0 for n in numbers)
all_positive = all(n > 0 for n in numbers)
print(f"\nNumbers: {numbers}")
print(f"Any even? {any_even}")
print(f"All positive? {all_positive}")
# Find first match
names = ["Alice", "Bob", "Charlie", "Diana"]
first_long = next((name for name in names if len(name) > 5), None)
print(f"First name > 5 chars: {first_long}")
# -----------------------------------------------------------------------------
# 8. Nested Comprehensions
# -----------------------------------------------------------------------------
print("\n--- Nested Comprehensions ---")
# Create a matrix
rows, cols = 3, 4
matrix = [[0 for _ in range(cols)] for _ in range(rows)]
print(f"Zero matrix {rows}x{cols}: {matrix}")
# Identity matrix
identity = [[1 if i == j else 0 for j in range(3)] for i in range(3)]
print("\nIdentity matrix:")
for row in identity:
print(f" {row}")
# Transpose matrix
original = [[1, 2, 3], [4, 5, 6]]
transposed = [[row[i] for row in original] for i in range(len(original[0]))]
print(f"\nOriginal: {original}")
print(f"Transposed: {transposed}")
# -----------------------------------------------------------------------------
# 9. When NOT to Use Comprehensions
# -----------------------------------------------------------------------------
print("\n--- When NOT to Use Comprehensions ---")
# 1. Complex logic - use regular loop
# BAD:
# result = [func1(x) if x > 0 else func2(x) if x < 0 else func3(x) for x in data if valid(x)]
# GOOD: Use regular loop for complex logic
def process_numbers(data):
result = []
for x in data:
if not x: # Skip None or 0
continue
if x > 0:
result.append(x ** 2)
else:
result.append(abs(x))
return result
# 2. Side effects - use regular loop
# BAD: [print(x) for x in items] # Creates unnecessary list
# GOOD:
# for x in items:
# print(x)
# 3. Very long comprehensions that require wrapping
# Consider regular loop for readability
print("Use regular loops when:")
print(" - Logic is complex")
print(" - There are side effects (print, modify, etc.)")
print(" - Comprehension becomes too long to read")
# -----------------------------------------------------------------------------
# 10. Practical Examples
# -----------------------------------------------------------------------------
print("\n--- Practical Examples ---")
# 1. Parse CSV-like data
csv_data = "name,age,city\nAlice,25,NYC\nBob,30,LA\nCharlie,35,Chicago"
rows = [line.split(",") for line in csv_data.split("\n")]
print(f"Parsed CSV: {rows}")
# 2. Filter and transform objects
users = [
{"name": "Alice", "age": 25, "active": True},
{"name": "Bob", "age": 17, "active": True},
{"name": "Charlie", "age": 30, "active": False},
{"name": "Diana", "age": 22, "active": True}
]
active_adults = [
user["name"]
for user in users
if user["active"] and user["age"] >= 18
]
print(f"\nActive adults: {active_adults}")
# 3. Word frequency (dict comprehension)
text = "the quick brown fox jumps over the lazy dog"
words = text.split()
frequency = {word: words.count(word) for word in set(words)}
print(f"\nWord frequency: {frequency}")
# 4. File path manipulation
files = ["report.pdf", "data.csv", "image.png", "document.pdf", "log.txt"]
pdf_files = [f for f in files if f.endswith(".pdf")]
print(f"\nPDF files: {pdf_files}")
# 5. Coordinate pairs
coords = [(x, y) for x in range(3) for y in range(3) if x != y]
print(f"\nCoordinate pairs (x != y): {coords}")