OIM3640 - Problem Solving and Software Design

2026 Spring

Session 12 (3/3)

contain

Today's Agenda

  • Announcements/Updates
  • What We've Learned So Far
  • Quiz 1 Review + Practice
  • Lecture: Chapter 9 - Lists
  • Spelling Bee Puzzle

Announcements/Updates

  • Mini Project 1 - keep working!
    • Aim to have core functionality by end of this week
    • Come to office hours if you're stuck
  • Communication
    • Office Hours: Walk-in or by appointment
    • Email: Specify course # in subject, e.g., "OIM3640: GitHub settings"
    • You are required to meet with me at least once this semester
  • Questions?

What We've Learned So Far

  • Python Fundamentals
    • Variables, types, functions, conditionals
  • Iteration & Patterns
    • for/while loops, search patterns (flag variables, early return, counters)
  • Strings: indexing, slicing, immutability, methods
  • Working with AI: Copilot Ask/Plan/Agent, reading AI-generated code

Quiz 1 Review: Q1 & Q2

Q1: git commit saves changes locally. git push uploads commits to the remote (GitHub).

Q2: What happens when you call has_vowel('python')?

def has_vowel(s):
    i = 0
    while i < len(s):
        if s[i] in 'aeiou':
            i += 1
            return True
    return False

has_digit

def has_digit(s):
    for c in s:
        if c.isdigit():
            return True
        else:
            return False
print(has_digit('iPhone15'))   # ?
print(has_digit('4ever'))      # ?
print(has_digit('hello'))      # ?

has_lower

def has_lower(s):
    for c in s:
        if 'c'.islower():
            return True
        else:
            return False
print(has_lower('NASA'))     # ?
print(has_lower('Python'))   # ?
print(has_lower('copilot'))      # ?

check_vowel

def check_vowel(s):
    for c in s:
        result = (c in 'aeiou')
    return result
print(check_vowel('orange'))   # ?
print(check_vowel('lemon'))    # ?
print(check_vowel('kiwi'))     # ?

What does this function actually check?

any_vowel

def any_vowel(s):
    flag = False
    for c in s:
        flag = flag or (c in 'aeiou')
    return flag
print(any_vowel('rhythm'))   # ?
print(any_vowel('cafe'))     # ?
print(any_vowel('sky'))      # ?

all_alpha

def all_alpha(s):
    flag = True
    for c in s:
        flag = flag and c.isalpha()
    return flag
print(all_alpha('Babson'))    # ?
print(all_alpha('OIM3640'))   # ?
print(all_alpha('hello!'))    # ?

has_space

def has_space(s):
    for c in s:
        if c == ' ':
            break
            return True
    return False
print(has_space('ice cream'))   # ?
print(has_space(' hello'))      # ?
print(has_space('pizza'))       # ?

all_digit

def all_digit(s):
    for c in s:
        if not c.isdigit():
            return False
    return True
print(all_digit('911'))      # ?
print(all_digit('3.14'))     # ?
print(all_digit('OIM3640'))  # ?

Is this function correct? How does it work?

📝 Spelling Bee Puzzle

Rules: Find words that...

  • Use only the 7 given letters
  • Must include the center letter
  • Are at least 4 letters long

How would you break this into functions?

Spelling Bee: My Approach

def uses_only(word, letters):
    """Does word use only the allowed letters?"""

def must_use(word, center):
    """Does word include the center letter?"""

def find_words(word_list, letters, center):
    """Find all valid words from a word list."""

def main():
    """Load words, set up puzzle, print results."""

Which function reminds you of all_digit? Which reminds you of has_digit?

Now let's ask Copilot to plan this. Does it agree?

📝 Your Turn: Spelling Bee

Option A: Implement the functions yourself, then compare with AI

Option B: Ask Copilot to plan it, read the plan, then implement

  1. Create spelling_bee.py in your code folder
  2. Use words.txt from your data/ folder
    • From code/ or notebooks/: open('../data/words.txt')
  3. Test with today's letters from NYT Spelling Bee

Done early?

  • Solve other NYT puzzles with code (Wordle, Connections...)
  • Design the Spelling Bee game itself (not the solver) - generate a puzzle from a word list!

Chapter 9 - Lists

What we'll learn:

  • Lists as mutable sequences
  • List operations and methods
  • Lists and strings (split, join)
  • Sorting
  • Aliasing (important!)

A List Is a Sequence

stocks = ['AAPL', 'GOOG', 'MSFT', 'AMZN']
prices = [182.30, 141.80, 415.20, 178.50]
mixed = ['AAPL', 182.30, True]    # can mix types
empty = []

Access elements the same way as strings:

stocks[0]          # 'AAPL'
stocks[-1]         # 'AMZN'
len(stocks)        # 4
'GOOG' in stocks   # True

Lists Are Mutable!

Unlike strings, you can change a list in place:

stocks = ['AAPL', 'GOOG', 'MSFT', 'AMZN']
stocks[2] = 'META'    # replace MSFT with META
stocks   # ['AAPL', 'GOOG', 'META', 'AMZN']

Compare with strings:

ticker = 'MSFT'
ticker[0] = 'X'   # TypeError! Strings are immutable.

This is the key difference between lists and strings.

List Slices

Same syntax as string slices:

stocks = ['AAPL', 'GOOG', 'META', 'AMZN']
stocks[1:3]    # ['GOOG', 'META']
stocks[:2]     # ['AAPL', 'GOOG']
stocks[2:]     # ['META', 'AMZN']
stocks[:]      # ['AAPL', 'GOOG', 'META', 'AMZN'] (copy!)

A slice returns a new list (not an alias).

List Methods

stocks = ['AAPL', 'GOOG', 'META']

stocks.append('TSLA')           # ['AAPL', 'GOOG', 'META', 'TSLA']
stocks.extend(['NVDA', 'AMZN']) # [..., 'TSLA', 'NVDA', 'AMZN']

stocks.pop()                    # returns 'AMZN' (removes last)
stocks.remove('META')           # removes first 'META'

Important: most list methods modify in place and return None!

result = stocks.append('NFLX')
print(result)   # None  (common trap!)

Lists and Strings

Convert between lists and strings:

list('AAPL')                          # ['A', 'A', 'P', 'L']

'AAPL,GOOG,META,AMZN'.split(',')     # ['AAPL', 'GOOG', 'META', 'AMZN']

','.join(['AAPL', 'GOOG', 'META'])   # 'AAPL,GOOG,META'

split() and join() are inverses of each other.

Sorting

sorted() returns a new sorted list (original unchanged):

stocks = ['GOOG', 'AAPL', 'META']
sorted(stocks)    # ['AAPL', 'GOOG', 'META']
stocks            # ['GOOG', 'AAPL', 'META']  (unchanged!)

Useful trick with strings:

''.join(sorted('listen'))   # 'eilnst'
''.join(sorted('silent'))   # 'eilnst'  — same! They're anagrams.

⚠️ Aliasing

Two variables can refer to the same list:

a = [1, 2, 3]
b = a          # b is NOT a copy — it's the SAME list!

b[0] = 99
print(a)       # [99, 2, 3]  — a changed too!

To make a copy:

b = a[:]       # slice copy
b = list(a)    # list() copy

This is a common source of bugs. Be careful when passing lists to functions!

The Accumulator Pattern with Lists

Build up a list inside a loop:

palindromes = []
for word in word_list:
    if word == word[::-1]:    # reverse the word
        palindromes.append(word)

This pattern is everywhere: filter a collection by some condition, collect results into a new list.

Before You Leave

  • Any questions?
  • Start your Learning Log for this week (logs/wk07.md)
  • Finish Spelling Bee if you didn't in class
  • Work on Chapter 9 exercises
  • Continue working on Mini Project 1
  • Push your work to GitHub

Next session: Dictionaries and Tuples (Chapters 10-11)

global styles

Answer: infinite loop. 'p' not in 'aeiou', so if-block never runs, i never advances. Fix: move i += 1 outside the if.

Answers: False, True, False — only checks FIRST character. 'iPhone15' SHOULD be True but 'i' isn't a digit. (same pattern as quiz check_1)

Answers: True, True, True — tests literal 'c', not variable c. 'c'.islower() is always True. 'NASA' has NO lowercase, 'copilot' is ALL lowercase — same result! (same pattern as quiz check_2)

Answers: True, False, True — only checks LAST character. 'orange' ends with 'e' (vowel), 'lemon' ends with 'n' (not vowel, but HAS vowels!), 'kiwi' ends with 'i'. (same pattern as quiz check_3)

Answers: False, True, False — or accumulator: once True stays True. Correctly checks "any vowel" (same pattern as quiz check_4)

Answers: True, False, False — and accumulator: once False stays False. Correctly checks "all alphabetic" (same pattern as quiz check_5)

Answers: False, False, False — return after break is UNREACHABLE. 'ice cream' and ' hello' SHOULD be True! (same pattern as quiz check_6)

Answers: True, False, False — early exit on non-digit, correct "all" pattern. '3.14' fails on '.', 'OIM3640' fails on 'O'. (same pattern as quiz check_7)