Skip to main content

Optional: Intermediate List Techniques

Explore nested lists, advanced slicing techniques, and Python tuples. Learn when and why to use these structures for more efficient data handling.

Introduction

Everything you've learned in the previous three lessons is enough to start building real automation scripts. You can create lists, modify them, and use methods to organize and analyze data.

This lesson is optional. It covers techniques that aren't essential for basic workflows but become useful as your scripts get more complex.

Come back to this lesson when you need these techniques. You'll know when that is — either because you hit a problem that these solve, or because you see them in someone else's code and want to understand what's happening.


Lesson Overview

This section contains a general overview of topics you will learn in this lesson.

  • Lists containing lists (nested lists)
  • Advanced slicing techniques
  • Introduction to tuples (immutable lists)
  • When you might need these techniques

Lists of Lists

A list can contain other lists. This is called a nested list or a list of lists.

Basic Example

# Rooms organized by floor
floor_1_rooms = ["Office 1", "Office 2"]
floor_2_rooms = ["Office 3", "Office 4"]

# Store both floors in one list
all_floors = [floor_1_rooms, floor_2_rooms]

print(all_floors)
# Output: [["Office 1", "Office 2"], ["Office 3", "Office 4"]]

Now all_floors is a list containing two lists.

Accessing Items

To access items in a nested list, use multiple indexes.

all_floors = [["Office 1", "Office 2"], ["Office 3", "Office 4"]]

# Get the first floor
first_floor = all_floors[0]
print(first_floor)
# Output: ["Office 1", "Office 2"]

# Get a specific room
room = all_floors[0][1]
print(room)
# Output: Office 2

The syntax all_floors[0][1] means:

  • all_floors[0] → Get the first floor list
  • [1] → Get the second item in that list

Architectural Example: Organizing Rooms by Floor

basement_rooms = ["Storage", "Mechanical"]
ground_rooms = ["Lobby", "Reception", "Office 1"]
first_rooms = ["Office 2", "Office 3", "Conference"]

building = [basement_rooms, ground_rooms, first_rooms]

# How many floors?
floor_count = len(building)
print(f"Floors: {floor_count}")
# Output: Floors: 3

# How many rooms on ground floor?
ground_floor_room_count = len(building[1])
print(f"Ground floor rooms: {ground_floor_room_count}")
# Output: Ground floor rooms: 3

# Print all floors and their rooms
for i, floor_rooms in enumerate(building):
    print(f"Floor {i}: {floor_rooms}")

# Output:
# Floor 0: ["Storage", "Mechanical"]
# Floor 1: ["Lobby", "Reception", "Office 1"]
# Floor 2: ["Office 2", "Office 3", "Conference"]

(The enumerate() function gives you both the index and the item. You'll see this more in Module 05.)


When to Use Lists of Lists

Lists of lists are useful when your data has natural layers or groups:

  • Rooms organized by floor
  • Sheets organized by discipline
  • Coordinates (list of [x, y, z] points)
  • Schedule data (list of rows, each row is a list of values)

Example: Sheet organization

arch_sheets = ["A-101", "A-102", "A-201"]
struct_sheets = ["S-101", "S-102"]
mep_sheets = ["M-101", "E-101"]

all_sheets = [arch_sheets, struct_sheets, mep_sheets]

# Total sheets across all disciplines
total = sum(len(discipline) for discipline in all_sheets)
print(f"Total sheets: {total}")
# Output: Total sheets: 7

Advanced Slicing

You've already seen basic slicing: my_list[start:end]. There's more you can do.

Step Values

You can specify a step value: my_list[start:end:step]

sheets = ["A-101", "A-102", "A-201", "A-202", "S-101", "S-102"]

# Every other item
every_other = sheets[::2]
print(every_other)
# Output: ["A-101", "A-201", "S-101"]

# Every third item
every_third = sheets[::3]
print(every_third)
# Output: ["A-101", "A-202"]

The syntax is [start:end:step]. If you omit start and end, it means "entire list."


Reversing with Slicing

A negative step reverses the list.

sheets = ["A-101", "A-102", "A-201", "A-202"]

reversed_sheets = sheets[::-1]

print(reversed_sheets)
# Output: ["A-202", "A-201", "A-102", "A-101"]

This creates a new reversed list without modifying the original.

Compare to .reverse():

sheets.reverse()  # Modifies original

vs

reversed_sheets = sheets[::-1]  # Creates new list, original unchanged

Copying a List

You can copy a list using slicing.

original = ["A-101", "A-102", "A-201"]

# Copy the list
copy = original[:]

# Modify the copy
copy.append("A-202")

print(original)  # Output: ["A-101", "A-102", "A-201"] (unchanged)
print(copy)      # Output: ["A-101", "A-102", "A-201", "A-202"]

Why does this matter? Because assigning lists doesn't create a copy:

original = ["A-101", "A-102"]
reference = original  # This does NOT create a copy

reference.append("A-201")

print(original)   # Output: ["A-101", "A-102", "A-201"] (changed!)
print(reference)  # Output: ["A-101", "A-102", "A-201"]

Both variables point to the same list. Changes to one affect the other.

To create a true copy:

copy = original[:]
# or
copy = original.copy()
# or
copy = list(original)

All three methods create an independent copy.


Architectural Example: Extracting Ranges

sheets = ["A-101", "A-102", "A-201", "A-202", "S-101", "S-102", "M-101"]

# First 4 sheets
first_four = sheets[:4]
print(first_four)
# Output: ["A-101", "A-102", "A-201", "A-202"]

# Last 3 sheets
last_three = sheets[-3:]
print(last_three)
# Output: ["S-102", "M-101"]

# Middle section
middle = sheets[2:5]
print(middle)
# Output: ["A-201", "A-202", "S-101"]

Tuples (Immutable Lists)

A tuple is like a list, but it can't be changed after creation. It's immutable.

Creating Tuples

Tuples use parentheses instead of square brackets.

# List (mutable)
room_list = ["Office 1", "Office 2"]

# Tuple (immutable)
room_tuple = ("Office 1", "Office 2")

You can access items the same way:

project_info = ("2024-001", "Community Center", "In Progress")

project_code = project_info[0]
print(project_code)  # Output: 2024-001

But you can't modify them:

project_info[0] = "2024-002"
# Error: TypeError: 'tuple' object does not support item assignment

You also can't add or remove items:

project_info.append("Approved")
# Error: AttributeError: 'tuple' object has no attribute 'append'

Why Use Tuples?

Tuples are for data that shouldn't change.

Use tuples when:

  • The data is fixed (coordinates, project metadata)
  • You want to prevent accidental modification
  • You're returning multiple values from a function (Module 06)

Examples:

# Project metadata (shouldn't change)
project = ("2024-001", "Community Center", "Smith Architects")

# A point in 3D space
point = (125.3, 78.9, 45.2)

# RGB color values
color = (255, 128, 0)

Unpacking Tuples

You can assign tuple values to multiple variables at once.

project_info = ("2024-001", "Community Center", "In Progress")

# Unpack into three variables
project_code, project_name, status = project_info

print(project_code)  # Output: 2024-001
print(project_name)  # Output: Community Center
print(status)        # Output: In Progress

This works with lists too, but it's most common with tuples.

Architectural Example:

# Point coordinates
point = (125.3, 78.9, 45.2)

x, y, z = point

print(f"X: {x}, Y: {y}, Z: {z}")
# Output: X: 125.3, Y: 78.9, Z: 45.2

Tuples vs Lists: When to Use Each

Use lists when:

  • Data might change (add, remove, modify items)
  • You're building a collection dynamically
  • You need list methods like .sort() or .append()

Use tuples when:

  • Data is fixed and shouldn't change
  • You want to ensure immutability
  • You're working with coordinates or structured records

In practice: You'll use lists 90% of the time. Tuples are for special cases.


Real Examples

Lists of Lists: Room Schedule

# Each room: [name, area, type]
rooms = [
    ["Office 1", 12.5, "Private"],
    ["Office 2", 15.3, "Private"],
    ["Conference", 45.8, "Meeting"],
    ["Break Room", 18.2, "Common"]
]

# Total area
total_area = sum(room[1] for room in rooms)
print(f"Total area: {total_area}m²")
# Output: Total area: 91.8m²

# Print each room
for room in rooms:
    name = room[0]
    area = room[1]
    room_type = room[2]
    print(f"{name}: {area}m² ({room_type})")

# Output:
# Office 1: 12.5m² (Private)
# Office 2: 15.3m² (Private)
# Conference: 45.8m² (Meeting)
# Break Room: 18.2m² (Common)

Tuples: Fixed Project Data

# Project metadata (shouldn't change)
project = ("2024-001", "Community Center", "Smith Architects", "In Progress")

# Unpack
code, name, architect, status = project

print(f"Project: {name}")
print(f"Code: {code}")
print(f"Architect: {architect}")
print(f"Status: {status}")

# Output:
# Project: Community Center
# Code: 2024-001
# Architect: Smith Architects
# Status: In Progress

Copying Lists Safely

original_sheets = ["A-101", "A-102", "A-201"]

# Wrong - creates reference, not copy
wrong_copy = original_sheets
wrong_copy.append("A-202")
print(original_sheets)
# Output: ["A-101", "A-102", "A-201", "A-202"] (modified!)

# Correct - creates independent copy
original_sheets = ["A-101", "A-102", "A-201"]
correct_copy = original_sheets[:]
correct_copy.append("A-202")
print(original_sheets)
# Output: ["A-101", "A-102", "A-201"] (unchanged)

When You'll Need These Techniques

Lists of lists:

  • When you start working with schedule data from Revit
  • When organizing elements by category or level
  • When processing CSV files (rows of data)

Advanced slicing:

  • When you need to copy lists
  • When extracting specific ranges
  • When reversing without mutation

Tuples:

  • When working with coordinates
  • When functions return multiple values (Module 06)
  • When you want to prevent accidental changes

You don't need to master these now. Just know they exist. When you encounter a situation where they'd help, you'll remember this lesson and come back.


Assignment

  1. Create a new file called intermediate_lists.py
  2. Create a list of lists for three floors:
    • Basement: ["Storage", "Mechanical"]
    • Ground: ["Lobby", "Office 1", "Office 2"]
    • First: ["Office 3", "Conference"]
  3. Store all three in a building list
  4. Access and print:
    • The second floor (Ground)
    • The first room on the ground floor ("Lobby")
    • The total number of floors
    • The total number of rooms (sum across all floors)
  5. Create a list: sheets = ["A-101", "A-102", "A-201", "A-202", "S-101", "S-102"]
  6. Use slicing to:
    • Get every other sheet
    • Reverse the list (without modifying the original)
    • Create a copy of the list
  7. Create a tuple for project info: ("2024-001", "Community Center", "Active")
  8. Unpack the tuple into three variables and print each
  9. Try to modify the tuple (append or change an item) — see the error
  10. Experiment:
    • Create a list and assign it to another variable
    • Modify the second variable
    • See that both variables changed (they reference the same list)
    • Now create a proper copy using [:] and verify it's independent

Knowledge Check

The following questions are an opportunity to reflect on key topics in this lesson.


Additional Resources

This section contains helpful links to related content. It isn't required, so consider it supplemental.

Updated on Mar 27, 2026