Why Data Structures Matter
How you organize data affects:
- Performance
- Readability
- Maintainability
- What operations are easy or hard
Choose wisely.
Arrays / Lists
What They Are
Ordered collections of items:
numbers = [1, 2, 3, 4, 5]
names = ["Alice", "Bob", "Charlie"]
mixed = [1, "hello", True, None]
When to Use
- Ordered data
- Lists of similar items
- When you need indexing
- When order matters
Operations
# Access by index
first = numbers[0] # 1
last = numbers[-1] # 5
# Add items
numbers.append(6) # Add to end
numbers.insert(0, 0) # Add at position
# Remove
numbers.pop() # Remove last
numbers.remove(3) # Remove value
# Search
3 in numbers # True (O(n))
numbers.index(3) # Position of 3
# Iterate
for num in numbers:
print(num)
Performance
| Operation | Time |
| Access by index | O(1) |
| Search | O(n) |
| Append | O(1) |
| Insert | O(n) |
| Remove | O(n) |
Objects / Dictionaries
What They Are
Key-value pairs:
user = {
"name": "Alice",
"age": 30,
"email": "alice@example.com"
}
When to Use
- Named fields
- Fast lookup by key
- Flexible structure
- Configuration/settings
Operations
# Access
name = user["name"]
age = user.get("age", 0) # With default
# Set
user["role"] = "admin"
# Remove
del user["age"]
user.pop("email")
# Check existence
"name" in user # True
# Iterate
for key in user:
print(key, user[key])
for key, value in user.items():
print(key, value)
Performance
| Operation | Time |
| Access by key | O(1) |
| Set | O(1) |
| Delete | O(1) |
| Search keys | O(1) |
Sets
What They Are
Unordered collections of unique items:
tags = {"python", "javascript", "rust"}
numbers = {1, 2, 3, 4, 5}
When to Use
- Unique items only
- Fast membership testing
- Set operations (union, intersection)
- Removing duplicates
Operations
# Add
tags.add("go")
# Remove
tags.remove("rust") # Raises if missing
tags.discard("rust") # Silent if missing
# Membership
"python" in tags # True (O(1))
# Set operations
a = {1, 2, 3}
b = {2, 3, 4}
a | b # Union: {1, 2, 3, 4}
a & b # Intersection: {2, 3}
a - b # Difference: {1}
Stacks
What They Are
Last-in, first-out (LIFO):
stack = []
stack.append(1) # Push
stack.append(2)
stack.append(3)
item = stack.pop() # 3
When to Use
- Undo functionality
- Parsing (parentheses matching)
- Backtracking algorithms
- Function call management
Queues
What They Are
First-in, first-out (FIFO):
from collections import deque
queue = deque()
queue.append(1) # Enqueue
queue.append(2)
item = queue.popleft() # 1
When to Use
- Task processing
- Message queues
- Breadth-first search
- Scheduling
Nested Structures
Lists of Objects
users = [
{"name": "Alice", "age": 30},
{"name": "Bob", "age": 25},
{"name": "Charlie", "age": 35}
]
# Access
first_name = users[0]["name"]
# Find
alice = next(u for u in users if u["name"] == "Alice")
Objects of Lists
data = {
"names": ["Alice", "Bob", "Charlie"],
"ages": [30, 25, 35],
"scores": [95, 87, 92]
}
Deep Nesting
config = {
"database": {
"primary": {
"host": "localhost",
"port": 5432
},
"replica": {
"host": "replica.example.com",
"port": 5432
}
}
}
# Access
primary_host = config["database"]["primary"]["host"]
Choosing the Right Structure
Access Pattern
| Need | Use |
| By index | Array |
| By key | Object/Dict |
| Unique items | Set |
| LIFO | Stack |
| FIFO | Queue |
Data Characteristics
| Characteristic | Use |
| Ordered | Array |
| Key-value pairs | Object |
| No duplicates needed | Set |
| Hierarchical | Nested objects |
Operation Frequency
| Frequent Operation | Best Choice |
| Append | Array |
| Lookup by key | Object |
| Membership test | Set |
| Insert middle | Linked list |
Common Patterns
Grouping by Key
items = [
{"type": "fruit", "name": "apple"},
{"type": "vegetable", "name": "carrot"},
{"type": "fruit", "name": "banana"}
]
# Group by type
grouped = {}
for item in items:
key = item["type"]
if key not in grouped:
grouped[key] = []
grouped[key].append(item)
# Result:
# {
# "fruit": [{"type": "fruit", "name": "apple"}, ...],
# "vegetable": [...]
# }
Counting
words = ["apple", "banana", "apple", "cherry", "apple"]
counts = {}
for word in words:
counts[word] = counts.get(word, 0) + 1
# Result: {"apple": 3, "banana": 1, "cherry": 1}
Index Lookup
users = [
{"id": 1, "name": "Alice"},
{"id": 2, "name": "Bob"}
]
# Create index
users_by_id = {u["id"]: u for u in users}
# Fast lookup
user = users_by_id[1] # O(1) instead of O(n)
JSON Compatibility
For data storage and APIs, stick to JSON-compatible types:
- Strings
- Numbers
- Booleans
- null/None
- Arrays
- Objects
Avoid:
- Sets (not JSON-serializable)
- Complex objects
- Functions
Conclusion
Choose data structures based on:
- What operations you need
- Performance requirements
- Data characteristics
- Readability and maintainability
The right structure makes code cleaner and faster.
Next: Algorithm Basics - Problem-solving patterns