Data Structures

Working with lists, tuples, dictionaries, and sets

Introduction

Data structures allow you to organize and store collections of data efficiently. Python provides four fundamental built-in data structures: lists (ordered, mutable), tuples (ordered, immutable), dictionaries (key-value pairs), and sets (unordered, unique elements). Each has its own characteristics and use cases, making Python versatile for handling different types of data.

Quick Comparison

Data StructureOrderedMutableUse Case
List✓ Yes✓ YesOrdered collection of items
Tuple✓ Yes✗ NoImmutable sequence of items
Dictionary✓ Yes*✓ YesKey-value pairs
Set✗ No✓ YesUnique unordered collection

*Dictionaries maintain insertion order (Python 3.7+)

Lists

Lists are ordered, mutable collections of items. They're one of the most commonly used data structures in Python.

Creating Lists

# Empty list
numbers = []
names = list()

# List with items
fruits = ["apple", "banana", "orange"]
numbers = [1, 2, 3, 4, 5]
mixed = [1, "hello", 3.14, True]  # Can contain different types

# List from range
numbers = list(range(5))  # [0, 1, 2, 3, 4]
numbers = list(range(1, 6))  # [1, 2, 3, 4, 5]

Accessing List Items

fruits = ["apple", "banana", "orange", "grape"]

# Access by index (0-based)
first = fruits[0]      # "apple"
second = fruits[1]     # "banana"
last = fruits[-1]      # "grape" (negative indexing)

# Slicing
first_two = fruits[0:2]     # ["apple", "banana"]
last_two = fruits[-2:]      # ["orange", "grape"]
middle = fruits[1:3]        # ["banana", "orange"]
all_items = fruits[:]       # Copy of entire list

Modifying Lists

fruits = ["apple", "banana"]

# Add items
fruits.append("orange")           # ["apple", "banana", "orange"]
fruits.insert(1, "grape")         # ["apple", "grape", "banana", "orange"]
fruits.extend(["mango", "kiwi"])  # Add multiple items

# Remove items
fruits.remove("banana")           # Remove first occurrence
fruits.pop()                      # Remove and return last item
fruits.pop(0)                     # Remove and return item at index 0
del fruits[1]                     # Delete item at index 1

# Modify items
fruits[0] = "pear"                # Replace item at index 0

List Methods and Operations

numbers = [3, 1, 4, 1, 5, 9, 2]

# Common methods
len(numbers)              # 7 (length)
numbers.count(1)          # 2 (count occurrences)
numbers.index(4)          # 2 (first index of value)
numbers.sort()            # Sort in place: [1, 1, 2, 3, 4, 5, 9]
numbers.reverse()         # Reverse in place
sorted(numbers)           # Return sorted copy (doesn't modify original)

# Concatenation
list1 = [1, 2, 3]
list2 = [4, 5, 6]
combined = list1 + list2  # [1, 2, 3, 4, 5, 6]

# Repetition
repeated = [0] * 5        # [0, 0, 0, 0, 0]

# Membership
"apple" in fruits         # True
"grape" not in fruits     # True

List Comprehension (Advanced)

List comprehensions provide a concise way to create lists:

# Traditional way
squares = []
for x in range(10):
    squares.append(x ** 2)

# List comprehension (more Pythonic)
squares = [x ** 2 for x in range(10)]  # [0, 1, 4, 9, 16, ...]

# With condition
evens = [x for x in range(10) if x % 2 == 0]  # [0, 2, 4, 6, 8]

Tuples

Tuples are ordered, immutable collections. Once created, you cannot modify them. They're useful for data that shouldn't change, like coordinates or database records.

Creating Tuples

# Empty tuple (rare)
empty = ()
empty = tuple()

# Tuple with items
coordinates = (10, 20)
point = 10, 20  # Parentheses optional (but recommended)
person = ("Alice", 30, "Engineer")

# Single item tuple (note the comma!)
single = (5,)   # Tuple
not_tuple = (5) # This is just an integer!

Accessing and Using Tuples

point = (10, 20)

# Access by index (same as lists)
x = point[0]      # 10
y = point[1]      # 20

# Slicing (returns new tuple)
first_two = point[:1]  # (10,)

# Unpacking
x, y = point      # x = 10, y = 20

# Multiple assignment
name, age, job = ("Alice", 30, "Engineer")

# Tuple methods
point.count(10)   # Count occurrences
point.index(20)   # Find index of value

# Cannot modify (immutable)
# point[0] = 5    # This will cause TypeError!

When to Use Tuples

✓ Good for Tuples
  • Coordinates (x, y)
  • RGB color values
  • Database records
  • Function return values
  • Dictionary keys (immutable requirement)
Use Lists Instead
  • When items need to change
  • When you need to add/remove items
  • For dynamic collections
  • When order matters but items change

Dictionaries

Dictionaries store data as key-value pairs. They're incredibly useful for organizing data with meaningful relationships, like a contact list or configuration settings.

Creating Dictionaries

# Empty dictionary
person = {}
person = dict()

# Dictionary with key-value pairs
person = {
    "name": "Alice",
    "age": 30,
    "city": "New York"
}

# Using dict() constructor
person = dict(name="Alice", age=30, city="New York")

# Dictionary with different value types
info = {
    "name": "Bob",
    "scores": [85, 90, 88],
    "active": True,
    "balance": 1250.50
}

Accessing Dictionary Values

person = {"name": "Alice", "age": 30}

# Access by key
name = person["name"]        # "Alice"
age = person["age"]          # 30

# Using get() (safer - returns None if key doesn't exist)
name = person.get("name")    # "Alice"
email = person.get("email")  # None (key doesn't exist)
email = person.get("email", "N/A")  # "N/A" (default value)

# Check if key exists
if "name" in person:
    print(person["name"])

# Keys must be immutable (strings, numbers, tuples)
# Lists cannot be keys!

Modifying Dictionaries

person = {"name": "Alice", "age": 30}

# Add or update items
person["city"] = "New York"     # Add new key-value
person["age"] = 31              # Update existing value
person.update({"city": "Boston", "job": "Engineer"})  # Update multiple

# Remove items
del person["age"]               # Remove key-value pair
city = person.pop("city")       # Remove and return value
person.popitem()                # Remove and return last item (Python 3.7+)
person.clear()                  # Remove all items

Dictionary Methods

person = {"name": "Alice", "age": 30, "city": "New York"}

# Get keys, values, items
person.keys()       # dict_keys(['name', 'age', 'city'])
person.values()     # dict_values(['Alice', 30, 'New York'])
person.items()      # dict_items([('name', 'Alice'), ('age', 30), ...])

# Convert to lists (if needed)
list(person.keys())   # ['name', 'age', 'city']
list(person.values()) # ['Alice', 30, 'New York']

# Length
len(person)         # 3

# Iterating
for key in person:
    print(key, person[key])

for key, value in person.items():
    print(key, value)

Nested Dictionaries

Dictionaries can contain other dictionaries, lists, and any data type:

students = {
    "alice": {
        "age": 20,
        "grades": [85, 90, 88],
        "active": True
    },
    "bob": {
        "age": 21,
        "grades": [78, 82, 80],
        "active": True
    }
}

# Access nested values
alice_age = students["alice"]["age"]        # 20
alice_first_grade = students["alice"]["grades"][0]  # 85

Sets

Sets are unordered collections of unique elements. They're perfect for removing duplicates, membership testing, and mathematical set operations.

Creating Sets

# Empty set (use set(), not {})
numbers = set()
# numbers = {}  # This creates a dictionary, not a set!

# Set with items
fruits = {"apple", "banana", "orange"}
numbers = {1, 2, 3, 4, 5}

# From a list (removes duplicates)
unique = set([1, 2, 2, 3, 3, 3])  # {1, 2, 3}

# Set comprehension
squares = {x ** 2 for x in range(5)}  # {0, 1, 4, 9, 16}

Set Operations

fruits = {"apple", "banana", "orange"}

# Adding and removing
fruits.add("grape")       # {"apple", "banana", "orange", "grape"}
fruits.remove("banana")   # Removes "banana" (raises error if not found)
fruits.discard("mango")   # Safe remove (no error if not found)
fruits.pop()              # Remove and return arbitrary element
fruits.clear()            # Remove all elements

# Set operations
set1 = {1, 2, 3, 4}
set2 = {3, 4, 5, 6}

set1.union(set2)           # {1, 2, 3, 4, 5, 6} (all unique elements)
set1 | set2                # Same as union

set1.intersection(set2)    # {3, 4} (common elements)
set1 & set2                # Same as intersection

set1.difference(set2)      # {1, 2} (in set1 but not set2)
set1 - set2                # Same as difference

set1.symmetric_difference(set2)  # {1, 2, 5, 6} (elements in either but not both)
set1 ^ set2                      # Same as symmetric_difference

Set Methods

numbers = {1, 2, 3, 4, 5}

# Membership testing (very fast!)
2 in numbers         # True
10 in numbers        # False

# Size
len(numbers)         # 5

# Set comparisons
set1 = {1, 2, 3}
set2 = {1, 2, 3, 4}

set1.issubset(set2)      # True (all elements of set1 in set2)
set1 <= set2             # Same
set2.issuperset(set1)    # True (set2 contains all of set1)
set2 >= set1             # Same
set1.isdisjoint({5, 6})  # True (no common elements)

Common Set Use Cases

# Remove duplicates from a list
numbers = [1, 2, 2, 3, 3, 3, 4]
unique = list(set(numbers))  # [1, 2, 3, 4]

# Fast membership testing
visited = set()
visited.add("page1")
if "page1" in visited:  # Very fast lookup!
    print("Already visited")

# Finding common elements
list1 = [1, 2, 3, 4]
list2 = [3, 4, 5, 6]
common = set(list1) & set(list2)  # {3, 4}

Practical Examples

Example: Student Grade Tracker

# Using a dictionary to track student grades
students = {
    "Alice": [85, 90, 88],
    "Bob": [78, 82, 80],
    "Charlie": [92, 95, 93]
}

# Add a new grade
students["Alice"].append(87)

# Calculate average grade
def average_grades(student_name):
    grades = students[student_name]
    return sum(grades) / len(grades)

# Get all student names (keys)
names = list(students.keys())

# Find students with average above 90
top_students = [
    name for name in students
    if average_grades(name) > 90
]

Example: Removing Duplicates and Finding Common Items

# Two shopping lists
list1 = ["apple", "banana", "orange", "milk", "bread"]
list2 = ["banana", "milk", "cheese", "yogurt"]

# Convert to sets for operations
set1 = set(list1)
set2 = set(list2)

# Items to buy (all unique items)
to_buy = set1 | set2  # Union

# Items in both lists
common = set1 & set2  # Intersection: {"banana", "milk"}

# Items only in first list
only_list1 = set1 - set2  # {"apple", "orange", "bread"}

# Convert back to list if needed
to_buy_list = list(to_buy)

Key Takeaways

Lists

  • Ordered, mutable collections
  • Use [ ] brackets
  • Perfect for sequences that change
  • Support indexing and slicing

Tuples

  • Ordered, immutable collections
  • Use ( ) parentheses
  • Good for fixed data
  • Can be dictionary keys

Dictionaries

  • Key-value pairs
  • Use { } braces
  • Fast lookups by key
  • Keys must be immutable

Sets

  • Unordered, unique elements
  • Use { } braces
  • Great for duplicates removal
  • Fast membership testing
What's Next?

Excellent! You now understand Python's core data structures. These are fundamental tools you'll use in almost every Python program. Next, we'll learn how to control the flow of your programs:

  • Conditional statements - Make decisions with if/elif/else
  • Loops - Iterate with for and while loops
  • Loop control - Use break and continue statements
  • Looping through structures - Iterate over lists, dictionaries, and sets