Dev In The Mountain Header
A Developer In The mountains having fun

Lists and Tuples in Python

Lists and tuples are fundamental data structures in Python for storing collections of items. They allow you to group related data together and perform operations on multiple values at once. Understanding these structures is essential for effective Python programming.

What are Lists?

A list is an ordered, mutable (changeable) collection that can hold items of different types.

# Creating lists
fruits = ['apple', 'banana', 'cherry']
numbers = [1, 2, 3, 4, 5]
mixed = [1, 'hello', 3.14, True]
empty_list = []

print(fruits)
print(f"Length: {len(fruits)}")

Key Characteristics of Lists

  • Ordered: Items maintain their position
  • Mutable: Can be modified after creation
  • Allow duplicates: Can contain the same value multiple times
  • Indexed: Access items by position (starting at 0)
  • Dynamic: Can grow or shrink in size

Creating Lists

# Various ways to create lists
# Direct assignment
colors = ['red', 'green', 'blue']

# Using list() constructor
numbers = list(range(5))  # [0, 1, 2, 3, 4]
letters = list('hello')   # ['h', 'e', 'l', 'l', 'o']

# Empty list
empty1 = []
empty2 = list()

# List with repeated values
zeros = [0] * 5  # [0, 0, 0, 0, 0]

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

print(f"Colors: {colors}")
print(f"Numbers: {numbers}")
print(f"Squares: {squares}")

Accessing List Elements

Indexing

fruits = ['apple', 'banana', 'cherry', 'date', 'elderberry']

# Access by index (0-based)
print(fruits[0])   # 'apple' (first item)
print(fruits[2])   # 'cherry' (third item)

# Negative indexing (from end)
print(fruits[-1])  # 'elderberry' (last item)
print(fruits[-2])  # 'date' (second from last)

# Get first and last
first = fruits[0]
last = fruits[-1]
print(f"First: {first}, Last: {last}")

Slicing

numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

# Basic slicing: list[start:end]
print(numbers[2:5])    # [2, 3, 4] (items 2, 3, 4)
print(numbers[:3])     # [0, 1, 2] (first 3)
print(numbers[7:])     # [7, 8, 9] (from 7 to end)
print(numbers[:])      # [0, 1, ... 9] (entire list copy)

# Slicing with step: list[start:end:step]
print(numbers[::2])    # [0, 2, 4, 6, 8] (every 2nd item)
print(numbers[1::2])   # [1, 3, 5, 7, 9] (odd indices)
print(numbers[::-1])   # [9, 8, 7, ... 0] (reversed)

# Negative indices in slicing
print(numbers[-3:])    # [7, 8, 9] (last 3)
print(numbers[:-2])    # [0, 1, ... 7] (all but last 2)

Modifying Lists

Changing Items

fruits = ['apple', 'banana', 'cherry']

# Change single item
fruits[1] = 'blueberry'
print(fruits)  # ['apple', 'blueberry', 'cherry']

# Change multiple items with slicing
numbers = [0, 1, 2, 3, 4, 5]
numbers[1:4] = [10, 20, 30]
print(numbers)  # [0, 10, 20, 30, 4, 5]

Adding Items

# append(): Add single item to end
fruits = ['apple', 'banana']
fruits.append('cherry')
print(fruits)  # ['apple', 'banana', 'cherry']

# insert(): Add item at specific position
fruits.insert(1, 'blueberry')
print(fruits)  # ['apple', 'blueberry', 'banana', 'cherry']

# extend(): Add multiple items
fruits.extend(['date', 'elderberry'])
print(fruits)  # ['apple', 'blueberry', 'banana', 'cherry', 'date', 'elderberry']

# Using + operator
more_fruits = fruits + ['fig', 'grape']
print(more_fruits)

# Using += operator
fruits += ['honeydew']
print(fruits)

Removing Items

fruits = ['apple', 'banana', 'cherry', 'date', 'banana']

# remove(): Remove first occurrence of value
fruits.remove('banana')
print(fruits)  # ['apple', 'cherry', 'date', 'banana']

# pop(): Remove and return item at index (default: last)
last_fruit = fruits.pop()
print(f"Removed: {last_fruit}")
print(fruits)

second_fruit = fruits.pop(1)
print(f"Removed: {second_fruit}")
print(fruits)

# del: Delete by index or slice
numbers = [0, 1, 2, 3, 4, 5]
del numbers[2]  # Remove item at index 2
print(numbers)

del numbers[1:3]  # Remove slice
print(numbers)

# clear(): Remove all items
fruits.clear()
print(fruits)  # []

List Methods

# Sort
numbers = [3, 1, 4, 1, 5, 9, 2, 6]
numbers.sort()  # Sort in place
print(numbers)  # [1, 1, 2, 3, 4, 5, 6, 9]

numbers.sort(reverse=True)  # Sort descending
print(numbers)  # [9, 6, 5, 4, 3, 2, 1, 1]

# sorted(): Return new sorted list (doesn't modify original)
original = [3, 1, 4, 1, 5]
sorted_list = sorted(original)
print(f"Original: {original}")
print(f"Sorted: {sorted_list}")

# reverse(): Reverse in place
numbers = [1, 2, 3, 4, 5]
numbers.reverse()
print(numbers)  # [5, 4, 3, 2, 1]

# count(): Count occurrences
fruits = ['apple', 'banana', 'apple', 'cherry', 'apple']
apple_count = fruits.count('apple')
print(f"Apples: {apple_count}")  # 3

# index(): Find first index of value
position = fruits.index('banana')
print(f"Banana is at index: {position}")  # 1

# copy(): Create shallow copy
original = [1, 2, 3]
copy1 = original.copy()
copy2 = original[:]  # Alternative
copy3 = list(original)  # Another alternative

Checking Membership

fruits = ['apple', 'banana', 'cherry']

# in operator
if 'apple' in fruits:
    print("We have apples!")

if 'orange' not in fruits:
    print("No oranges available")

# Check for any or all conditions
numbers = [2, 4, 6, 8, 10]
all_even = all(n % 2 == 0 for n in numbers)
print(f"All even: {all_even}")  # True

has_large = any(n > 15 for n in numbers)
print(f"Has number > 15: {has_large}")  # False

Looping Through Lists

fruits = ['apple', 'banana', 'cherry']

# Basic loop
for fruit in fruits:
    print(fruit)

# With index using enumerate
for index, fruit in enumerate(fruits):
    print(f"{index}: {fruit}")

# Start counting from 1
for position, fruit in enumerate(fruits, start=1):
    print(f"{position}. {fruit}")

# Loop with range and index
for i in range(len(fruits)):
    print(f"fruits[{i}] = {fruits[i]}")

# Reverse iteration
for fruit in reversed(fruits):
    print(fruit)

List Comprehensions

Compact way to create lists based on existing lists or ranges.

# Basic comprehension
squares = [x**2 for x in range(10)]
print(squares)  # [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

# With condition
even_squares = [x**2 for x in range(10) if x % 2 == 0]
print(even_squares)  # [0, 4, 16, 36, 64]

# Transform strings
names = ['alice', 'bob', 'charlie']
capitalized = [name.upper() for name in names]
print(capitalized)  # ['ALICE', 'BOB', 'CHARLIE']

# Nested comprehension
matrix = [[i*j for j in range(1, 4)] for i in range(1, 4)]
print(matrix)
# [[1, 2, 3], [2, 4, 6], [3, 6, 9]]

# Filter and transform
numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
doubled_evens = [x * 2 for x in numbers if x % 2 == 0]
print(doubled_evens)  # [4, 8, 12, 16, 20]

What are Tuples?

A tuple is an ordered, immutable (unchangeable) collection.

# Creating tuples
fruits_tuple = ('apple', 'banana', 'cherry')
numbers_tuple = (1, 2, 3, 4, 5)
mixed_tuple = (1, 'hello', 3.14, True)

# Single element tuple (note the comma!)
single = (42,)  # Tuple with one element
not_tuple = (42)  # This is just an integer!

# Without parentheses (tuple packing)
point = 10, 20, 30
print(type(point))  # <class 'tuple'>

# Empty tuple
empty = ()

Key Characteristics of Tuples

  • Ordered: Items maintain their position
  • Immutable: Cannot be modified after creation
  • Allow duplicates: Can contain the same value multiple times
  • Indexed: Access items by position (starting at 0)
  • Faster than lists: Due to immutability
  • Can be dictionary keys: Because they're hashable

Accessing Tuple Elements

point = (10, 20, 30, 40, 50)

# Indexing (same as lists)
print(point[0])   # 10
print(point[-1])  # 50

# Slicing (same as lists)
print(point[1:4])   # (20, 30, 40)
print(point[:3])    # (10, 20, 30)
print(point[::2])   # (10, 30, 50)

# Tuple unpacking
x, y, z = (10, 20, 30)
print(f"x={x}, y={y}, z={z}")

# Unpacking with * (rest)
first, *middle, last = (1, 2, 3, 4, 5)
print(f"First: {first}")
print(f"Middle: {middle}")  # [2, 3, 4]
print(f"Last: {last}")

Tuple Methods (Limited Due to Immutability)

numbers = (1, 2, 3, 2, 4, 2, 5)

# count(): Count occurrences
count_of_2 = numbers.count(2)
print(f"Number of 2s: {count_of_2}")  # 3

# index(): Find first occurrence
position = numbers.index(4)
print(f"4 is at index: {position}")  # 4

# Length
print(f"Length: {len(numbers)}")

# Check membership
if 3 in numbers:
    print("3 is in the tuple")

Why Use Tuples?

1. Immutability Guarantees Data Safety

# Coordinates shouldn't change
point = (10, 20)

# This would cause an error:
# point[0] = 15  # TypeError: 'tuple' object does not support item assignment

# Use tuples for constants
RGB_RED = (255, 0, 0)
RGB_GREEN = (0, 255, 0)
RGB_BLUE = (0, 0, 255)

2. As Dictionary Keys

# Tuples can be dictionary keys; lists cannot
locations = {}
locations[(0, 0)] = "Origin"
locations[(10, 20)] = "Point A"
locations[(-5, 15)] = "Point B"

print(locations[(0, 0)])  # "Origin"

# Lists cannot be keys:
# locations[[1, 2]] = "Won't work"  # TypeError

3. Multiple Return Values from Functions

def get_min_max(numbers):
    """Return both minimum and maximum"""
    return min(numbers), max(numbers)

# Returns a tuple
result = get_min_max([5, 2, 8, 1, 9])
print(result)  # (1, 9)

# Unpack immediately
minimum, maximum = get_min_max([5, 2, 8, 1, 9])
print(f"Min: {minimum}, Max: {maximum}")

4. Performance

import sys

list_example = [1, 2, 3, 4, 5]
tuple_example = (1, 2, 3, 4, 5)

# Tuples use less memory
print(f"List size: {sys.getsizeof(list_example)} bytes")
print(f"Tuple size: {sys.getsizeof(tuple_example)} bytes")

# Tuples are faster to create and iterate

Converting Between Lists and Tuples

# List to tuple
my_list = [1, 2, 3, 4, 5]
my_tuple = tuple(my_list)
print(my_tuple)  # (1, 2, 3, 4, 5)

# Tuple to list
my_tuple = (1, 2, 3, 4, 5)
my_list = list(my_tuple)
print(my_list)  # [1, 2, 3, 4, 5]

# Modify tuple by converting
original_tuple = (1, 2, 3)
temp_list = list(original_tuple)
temp_list.append(4)
new_tuple = tuple(temp_list)
print(new_tuple)  # (1, 2, 3, 4)

Practical Examples

Example 1: Shopping Cart

# Using list for mutable shopping cart
cart = []

# Add items
cart.append({'name': 'Apple', 'price': 0.5, 'qty': 5})
cart.append({'name': 'Banana', 'price': 0.3, 'qty': 10})
cart.append({'name': 'Orange', 'price': 0.6, 'qty': 3})

# Calculate total
total = 0
for item in cart:
    item_total = item['price'] * item['qty']
    print(f"{item['name']}: ${item_total:.2f}")
    total += item_total

print(f"\nTotal: ${total:.2f}")

# Remove an item
cart.remove(cart[1])  # Remove banana

Example 2: Student Grade Management

# Store student grades
students = [
    {'name': 'Alice', 'grades': [85, 92, 78, 90]},
    {'name': 'Bob', 'grades': [75, 88, 82, 86]},
    {'name': 'Charlie', 'grades': [95, 89, 93, 91]}
]

# Calculate averages
for student in students:
    grades = student['grades']
    average = sum(grades) / len(grades)
    print(f"{student['name']}: {average:.1f}")

# Find top student
best_student = max(students, key=lambda s: sum(s['grades']) / len(s['grades']))
print(f"\nTop student: {best_student['name']}")

Example 3: Coordinate System

# Using tuples for immutable coordinates
points = [
    (0, 0),    # Origin
    (10, 20),  # Point A
    (15, 25),  # Point B
    (5, 30)    # Point C
]

# Calculate distances from origin
import math

for point in points:
    x, y = point
    distance = math.sqrt(x**2 + y**2)
    print(f"Point {point}: distance = {distance:.2f}")

# Find furthest point
furthest = max(points, key=lambda p: p[0]**2 + p[1]**2)
print(f"Furthest point: {furthest}")

Example 4: Data Processing Pipeline

# Process list of numbers
data = [15, 23, 8, 42, 16, 31, 27, 4, 19]

# Filter: Keep only even numbers
even_numbers = [x for x in data if x % 2 == 0]
print(f"Even numbers: {even_numbers}")

# Map: Square all numbers
squared = [x**2 for x in data]
print(f"Squared: {squared}")

# Reduce: Find sum
total = sum(data)
print(f"Sum: {total}")

# Chain operations
result = sum([x**2 for x in data if x % 2 == 0])
print(f"Sum of squares of evens: {result}")

Example 5: Nested Lists (Matrix Operations)

# Represent a matrix
matrix = [
    [1, 2, 3],
    [4, 5, 6],
    [7, 8, 9]
]

# Print matrix
for row in matrix:
    print(row)

# Access elements
print(f"Element at [1][2]: {matrix[1][2]}")  # 6

# Sum all elements
total = sum(sum(row) for row in matrix)
print(f"Sum of all elements: {total}")

# Transpose matrix
transposed = [[matrix[j][i] for j in range(len(matrix))] 
              for i in range(len(matrix[0]))]
print("\nTransposed:")
for row in transposed:
    print(row)

Common Patterns

Pattern 1: Find Maximum/Minimum

numbers = [15, 23, 8, 42, 16, 31, 27]

# Using built-in functions
maximum = max(numbers)
minimum = min(numbers)
print(f"Max: {maximum}, Min: {minimum}")

# Manual approach
max_val = numbers[0]
for num in numbers:
    if num > max_val:
        max_val = num
print(f"Maximum: {max_val}")

Pattern 2: Remove Duplicates

# Remove duplicates while preserving order
numbers = [1, 2, 3, 2, 4, 3, 5, 1]

# Using set (loses order)
unique = list(set(numbers))

# Preserving order
unique_ordered = []
for num in numbers:
    if num not in unique_ordered:
        unique_ordered.append(num)

print(f"Unique (ordered): {unique_ordered}")

Pattern 3: Flatten Nested List

# Flatten list of lists
nested = [[1, 2, 3], [4, 5], [6, 7, 8, 9]]

# Using list comprehension
flat = [item for sublist in nested for item in sublist]
print(f"Flattened: {flat}")

# Using extend
flat = []
for sublist in nested:
    flat.extend(sublist)
print(f"Flattened: {flat}")

Common Mistakes

Mistake 1: Confusing append and extend

# append adds the entire object
my_list = [1, 2, 3]
my_list.append([4, 5])
print(my_list)  # [1, 2, 3, [4, 5]] - nested!

# extend adds individual items
my_list = [1, 2, 3]
my_list.extend([4, 5])
print(my_list)  # [1, 2, 3, 4, 5] - flat!

Mistake 2: Modifying List While Iterating

# WRONG: Don't modify list during iteration
numbers = [1, 2, 3, 4, 5]
for num in numbers:
    if num % 2 == 0:
        numbers.remove(num)  # Dangerous!

# CORRECT: Create new list
numbers = [1, 2, 3, 4, 5]
odd_numbers = [num for num in numbers if num % 2 != 0]

Mistake 3: Forgetting Tuple Comma

# This is NOT a tuple!
not_tuple = (42)
print(type(not_tuple))  # <class 'int'>

# This IS a tuple
is_tuple = (42,)
print(type(is_tuple))  # <class 'tuple'>

Practice Exercises

Exercise 1: List Statistics

Create a program that:

  • Takes a list of numbers
  • Calculates mean, median, and mode
  • Finds numbers above/below average

Exercise 2: Todo List Manager

Build a simple todo list with:

  • Add task
  • Remove task
  • Mark task as complete
  • Display all tasks

Exercise 3: Student Records

Create a system to:

  • Store student records (name, grades tuple)
  • Calculate GPA for each student
  • Find honor roll students (GPA > 3.5)
  • Sort students by GPA

Sample Solutions

Exercise 1:

def calculate_statistics(numbers):
    # Mean
    mean = sum(numbers) / len(numbers)
    
    # Median
    sorted_nums = sorted(numbers)
    n = len(sorted_nums)
    median = sorted_nums[n//2] if n % 2 == 1 else (sorted_nums[n//2-1] + sorted_nums[n//2]) / 2
    
    # Mode
    from collections import Counter
    counts = Counter(numbers)
    mode = counts.most_common(1)[0][0]
    
    # Above/below average
    above = [n for n in numbers if n > mean]
    below = [n for n in numbers if n < mean]
    
    return {
        'mean': mean,
        'median': median,
        'mode': mode,
        'above_avg': len(above),
        'below_avg': len(below)
    }

numbers = [15, 23, 8, 42, 16, 31, 27, 23, 19]
stats = calculate_statistics(numbers)
print(stats)

Key Takeaways

Lists:

  • Mutable, ordered collections
  • Use for data that changes
  • Rich set of methods (append, remove, sort, etc.)
  • Use square brackets []

Tuples:

  • Immutable, ordered collections
  • Use for data that shouldn't change
  • Faster and more memory-efficient
  • Can be dictionary keys
  • Use parentheses ()

When to Use Which:

  • List: Shopping cart, todo list, game scores
  • Tuple: Coordinates, RGB colors, function returns, dictionary keys

What's Next?

Now that you understand lists and tuples:


Lists and tuples are the foundation of data storage in Python. Master these structures and you'll be able to organize and manipulate data efficiently!

More places to find me
Mental Health
follow me on Mastodon