Data Structures: Organizing Your Data Like a Pro
Welcome to the world of data structures! Think of them as containers for your data - each with different strengths and use cases. Just like you wouldn’t carry groceries in a backpack the same way you’d carry books, different data needs different structures.
Why Data Structures Matter
Real-Life Analogy: Organizing Your Room
- Lists: Like a shopping list - ordered items you can add/remove
- Tuples: Like coordinates on a map - fixed, unchanging positions
- Dictionaries: Like a phone book - name → number lookup
- Sets: Like a guest list - unique items, order doesn’t matter
Code Benefits
# Without proper data structures (bad)
student1_name = "Alice"
student1_age = 20
student1_grade = "A"
student2_name = "Bob"
student2_age = 22
student2_grade = "B"
# With data structures (good)
students = [
{"name": "Alice", "age": 20, "grade": "A"},
{"name": "Bob", "age": 22, "grade": "B"}
]
Method 1: Lists - Ordered, Mutable Collections
What are Lists?
Lists are like shopping lists - ordered collections of items that you can modify.
# Creating lists
empty_list = []
numbers = [1, 2, 3, 4, 5]
fruits = ["apple", "banana", "orange"]
mixed = [1, "hello", True, 3.14]
Basic List Operations
fruits = ["apple", "banana", "orange"]
# Access elements (zero-indexed)
print(fruits[0]) # "apple"
print(fruits[1]) # "banana"
print(fruits[-1]) # "orange" (last element)
# Modify elements
fruits[1] = "grape"
print(fruits) # ["apple", "grape", "orange"]
# Add elements
fruits.append("kiwi") # Add to end
fruits.insert(1, "banana") # Insert at position 1
print(fruits) # ["apple", "banana", "grape", "orange", "kiwi"]
# Remove elements
fruits.remove("grape") # Remove by value
popped = fruits.pop() # Remove and return last element
print(fruits) # ["apple", "banana", "orange"]
print(f"Popped: {popped}") # "kiwi"
List Slicing
numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
# Basic slicing [start:end]
print(numbers[2:5]) # [2, 3, 4]
print(numbers[:3]) # [0, 1, 2] (from start to index 3)
print(numbers[7:]) # [7, 8, 9] (from index 7 to end)
# With step [start:end:step]
print(numbers[::2]) # [0, 2, 4, 6, 8] (every 2nd element)
print(numbers[1::2]) # [1, 3, 5, 7, 9] (every 2nd starting from index 1)
print(numbers[::-1]) # [9, 8, 7, 6, 5, 4, 3, 2, 1, 0] (reverse)
# Replace multiple elements
numbers[2:5] = [20, 30, 40]
print(numbers) # [0, 1, 20, 30, 40, 5, 6, 7, 8, 9]
List Methods
fruits = ["apple", "banana", "orange", "apple"]
# Count occurrences
print(fruits.count("apple")) # 2
# Find index
print(fruits.index("banana")) # 1
# Sort the list
fruits.sort()
print(fruits) # ["apple", "apple", "banana", "orange"]
# Reverse the list
fruits.reverse()
print(fruits) # ["orange", "banana", "apple", "apple"]
# Create sorted copy without modifying original
original = ["c", "a", "b"]
sorted_copy = sorted(original)
print(original) # ["c", "a", "b"]
print(sorted_copy) # ["a", "b", "c"]
Method 2: Tuples - Immutable Ordered Collections
What are Tuples?
Tuples are like GPS coordinates - fixed collections that cannot be changed after creation.
# Creating tuples
empty_tuple = ()
single_item = (42,) # Note the comma!
coordinates = (10, 20)
person = ("Alice", 25, "Engineer")
# Parentheses are optional
colors = "red", "green", "blue"
print(type(colors)) # <class 'tuple'>
Tuple Operations
point = (10, 20, 30)
# Access elements (same as lists)
print(point[0]) # 10
print(point[-1]) # 30
# Slicing (same as lists)
print(point[1:]) # (20, 30)
# Tuples are immutable - cannot modify!
# point[0] = 15 # TypeError!
# But you can create new tuples
new_point = (15,) + point[1:]
print(new_point) # (15, 20, 30)
When to Use Tuples vs Lists
# Use tuples for:
# 1. Coordinates
locations = [(40.7128, -74.0060), (34.0522, -118.2437)] # NYC, LA
# 2. Function returns
def get_user_info():
return ("Alice", 25, "alice@email.com") # Always 3 values
# 3. Dictionary keys (lists cannot be keys)
student_grades = {
("Alice", "Smith"): "A",
("Bob", "Jones"): "B"
}
# Use lists for:
# 1. Collections that change
shopping_list = ["milk", "bread", "eggs"]
shopping_list.append("butter") # Can add items
# 2. Sorting and modifying
numbers = [3, 1, 4, 1, 5]
numbers.sort() # [1, 1, 3, 4, 5]
Method 3: Dictionaries - Key-Value Pairs
What are Dictionaries?
Dictionaries are like phone books - you look up information using keys instead of positions.
# Creating dictionaries
empty_dict = {}
person = {
"name": "Alice",
"age": 25,
"city": "New York"
}
# Different key types
mixed_keys = {
"string_key": "value",
42: "number key",
(1, 2): "tuple key" # tuples can be keys, lists cannot
}
Dictionary Operations
person = {"name": "Alice", "age": 25, "city": "New York"}
# Access values
print(person["name"]) # "Alice"
print(person.get("age")) # 25
# Safe access (no KeyError if key doesn't exist)
print(person.get("salary", "Not specified")) # "Not specified"
# Add/modify values
person["job"] = "Engineer"
person["age"] = 26 # Update existing value
print(person)
# Remove values
removed_city = person.pop("city")
print(f"Removed: {removed_city}")
print(person)
# Check if key exists
if "name" in person:
print("Name is in dictionary")
# Get all keys, values, or items
print(person.keys()) # dict_keys(['name', 'age', 'job'])
print(person.values()) # dict_values(['Alice', 26, 'Engineer'])
print(person.items()) # dict_items([('name', 'Alice'), ('age', 26), ('job', 'Engineer')])
Dictionary Comprehension
# Create dictionary from list
numbers = [1, 2, 3, 4, 5]
squares = {x: x**2 for x in numbers}
print(squares) # {1: 1, 2: 4, 3: 9, 4: 16, 5: 25}
# Filter dictionary
original = {"a": 1, "b": 2, "c": 3, "d": 4}
even_values = {k: v for k, v in original.items() if v % 2 == 0}
print(even_values) # {"b": 2, "d": 4}
Method 4: Sets - Unique Collections
What are Sets?
Sets are like guest lists - they contain unique items and order doesn’t matter.
# Creating sets
empty_set = set() # {} creates empty dict, not set!
numbers = {1, 2, 3, 4, 5}
fruits = {"apple", "banana", "orange"}
# From list (removes duplicates)
duplicates = [1, 2, 2, 3, 3, 3]
unique_numbers = set(duplicates)
print(unique_numbers) # {1, 2, 3}
Set Operations
set_a = {1, 2, 3, 4, 5}
set_b = {4, 5, 6, 7, 8}
# Add elements
set_a.add(6)
print(set_a) # {1, 2, 3, 4, 5, 6}
# Remove elements
set_a.remove(6) # Raises KeyError if not found
set_a.discard(10) # No error if not found
# Set operations
print(set_a | set_b) # Union: {1, 2, 3, 4, 5, 6, 7, 8}
print(set_a & set_b) # Intersection: {4, 5}
print(set_a - set_b) # Difference: {1, 2, 3}
print(set_a ^ set_b) # Symmetric difference: {1, 2, 3, 6, 7, 8}
Real-World Examples
Example 1: Student Grade Book
# Using dictionaries and lists together
students = [
{
"name": "Alice",
"grades": [85, 92, 88],
"subjects": {"math": 85, "science": 92, "english": 88}
},
{
"name": "Bob",
"grades": [78, 85, 90],
"subjects": {"math": 78, "science": 85, "english": 90}
}
]
# Calculate average grade for each student
for student in students:
avg_grade = sum(student["grades"]) / len(student["grades"])
print(f"{student['name']}'s average: {avg_grade:.1f}")
# Find students who got A in math
math_a_students = [
student["name"]
for student in students
if student["subjects"]["math"] >= 90
]
print(f"Math A students: {math_a_students}")
Example 2: Inventory Management
# Using sets for categories and dictionaries for products
products = {
"laptop": {"price": 999, "stock": 5, "category": "electronics"},
"book": {"price": 20, "stock": 50, "category": "education"},
"headphones": {"price": 149, "stock": 12, "category": "electronics"}
}
categories = set()
for product in products.values():
categories.add(product["category"])
print(f"Categories: {categories}")
# Find low stock items
low_stock = [
name for name, info in products.items()
if info["stock"] < 10
]
print(f"Low stock items: {low_stock}")
# Calculate total inventory value
total_value = sum(info["price"] * info["stock"] for info in products.values())
print(f"Total inventory value: ${total_value}")
Example 3: Social Network
# Using sets for unique relationships
social_network = {
"Alice": {"friends": {"Bob", "Charlie"}, "interests": {"coding", "music"}},
"Bob": {"friends": {"Alice", "Diana"}, "interests": {"music", "sports"}},
"Charlie": {"friends": {"Alice"}, "interests": {"coding", "gaming"}},
"Diana": {"friends": {"Bob"}, "interests": {"sports", "reading"}}
}
# Find mutual friends
alice_friends = social_network["Alice"]["friends"]
bob_friends = social_network["Bob"]["friends"]
mutual_friends = alice_friends & bob_friends
print(f"Alice and Bob's mutual friends: {mutual_friends}")
# Find people with shared interests
def find_shared_interests(person1, person2):
interests1 = social_network[person1]["interests"]
interests2 = social_network[person2]["interests"]
return interests1 & interests2
shared = find_shared_interests("Alice", "Bob")
print(f"Alice and Bob's shared interests: {shared}")
# Suggest friends based on mutual friends
def suggest_friends(person):
friends = social_network[person]["friends"]
suggestions = set()
for friend in friends:
friend_friends = social_network[friend]["friends"]
# Add friends of friends (excluding self and direct friends)
suggestions.update(friend_friends - friends - {person})
return suggestions
alice_suggestions = suggest_friends("Alice")
print(f"Friend suggestions for Alice: {alice_suggestions}")
Common Data Structure Patterns
Pattern 1: Counter
# Count word frequencies
text = "the quick brown fox jumps over the lazy dog the fox is quick"
words = text.split()
word_count = {}
for word in words:
word_count[word] = word_count.get(word, 0) + 1
print(word_count)
# {'the': 2, 'quick': 2, 'brown': 1, 'fox': 2, 'jumps': 1, 'over': 1, 'lazy': 1, 'dog': 1, 'is': 1}
Pattern 2: Group By
# Group students by grade
students = [
{"name": "Alice", "grade": "A"},
{"name": "Bob", "grade": "B"},
{"name": "Charlie", "grade": "A"},
{"name": "Diana", "grade": "C"}
]
grade_groups = {}
for student in students:
grade = student["grade"]
if grade not in grade_groups:
grade_groups[grade] = []
grade_groups[grade].append(student["name"])
print(grade_groups)
# {'A': ['Alice', 'Charlie'], 'B': ['Bob'], 'C': ['Diana']}
Pattern 3: Stack (LIFO)
# Browser back button simulation
browser_history = []
def visit_page(page):
browser_history.append(page)
print(f"Visited: {page}")
def go_back():
if browser_history:
last_page = browser_history.pop()
print(f"Went back from: {last_page}")
if browser_history:
print(f"Now on: {browser_history[-1]}")
else:
print("No more pages in history")
else:
print("Cannot go back - no history")
visit_page("google.com")
visit_page("github.com")
visit_page("stackoverflow.com")
go_back()
go_back()
go_back()
go_back() # Try to go back too many times
Pattern 4: Queue (FIFO)
# Print job queue
print_queue = []
def add_print_job(document):
print_queue.append(document)
print(f"Added to queue: {document}")
def process_print_job():
if print_queue:
job = print_queue.pop(0) # Remove from front
print(f"Printing: {job}")
else:
print("No jobs in queue")
add_print_job("report.pdf")
add_print_job("presentation.pptx")
add_print_job("resume.docx")
process_print_job()
process_print_job()
process_print_job()
process_print_job() # Try to process when queue is empty
Performance Considerations
Time Complexity
# List operations
my_list = [1, 2, 3, 4, 5]
my_list.append(6) # O(1) - fast
my_list.insert(0, 0) # O(n) - slow for large lists
5 in my_list # O(n) - slow for large lists
# Dictionary operations
my_dict = {"a": 1, "b": 2}
my_dict["c"] = 3 # O(1) - fast
"c" in my_dict # O(1) - fast
my_dict["c"] # O(1) - fast
# Set operations
my_set = {1, 2, 3}
my_set.add(4) # O(1) - fast
4 in my_set # O(1) - fast
Practice Exercises
Exercise 1: To-Do List Application
Create a to-do list that supports:
- Adding tasks
- Marking tasks as complete
- Removing tasks
- Listing all/active/completed tasks
Exercise 2: Student Grade Analyzer
Create a system that:
- Stores student information (name, grades, subjects)
- Calculates averages
- Finds top performers
- Groups students by grade ranges
Exercise 3: Library Management System
Build a library system with:
- Books (title, author, ISBN, available copies)
- Members (name, ID, borrowed books)
- Borrowing/returning functionality
- Search by title/author
Exercise 4: Recipe Manager
Create a recipe manager that:
- Stores recipes (name, ingredients, instructions)
- Searches recipes by ingredient
- Suggests recipes based on available ingredients
- Scales recipes for different servings
Exercise 5: Music Playlist Manager
Build a playlist system with:
- Songs (title, artist, album, duration)
- Playlists (name, songs)
- Add/remove songs from playlists
- Calculate total playlist duration
- Find songs by artist/album
Summary
Data structures are the foundation of organized programming:
- Lists: Ordered, mutable collections
[1, 2, 3] - Tuples: Ordered, immutable collections
(1, 2, 3) - Dictionaries: Key-value pairs
{"key": "value"} - Sets: Unique, unordered collections
{1, 2, 3}
Choose the right structure for your needs:
- Use lists for ordered collections that change
- Use tuples for fixed collections of related data
- Use dictionaries for named data with fast lookup
- Use sets for unique items and mathematical operations
Next: Advanced Data Structures - stacks, queues, and trees! 🌳