Session 25

Lists and Problem Decomposition

CS 1510
Introduction to Computing

Quick Exercise: Homework 10

the puzzle master, Will Shortz

Now that Homework 10 is in the books, answer me questions three:

I'll tabulate your answers, and we'll return to the assignment later. First, write me some happy code.

Quick Exercise: Happy Numbers

Choose a two-digit number. Square each digit. Add the squares together to get a new number. Repeat this process until you reach 1 or until you see a number repeat itself.

If you reach 1, then the number you started with is a happy number. If you hit a cycle, then the number you started with is unhappy.

For example, 13 is happy, because 13 → 12 + 32 = 10 → 12 + 02 = 1. 4 is unhappy, because it generates the sequence 4, 16, 37, 58, 89, 145, 42, 20, 4, which repeats.

Write a Python function is_happy(n) that returns True if n is happy and False otherwise.

You may assume that we have already written the function sum_of_digits_squared(n). (You should try to write it yourself, as a study problem.)

Hint: A list might be handy...

The answer is hidden below.

Review of Homework 10

Easy. If you were looking for ways to save time or energy, reading all the problems ahead of time was worth the effort. Puzzles (g) and (j) were gimmes! And we had already solved Puzzle (k) back in Session19.

Hard. Puzzle (b) challenged me. When I saw the same idea pop up in Puzzles (f) and (i), I was glad to be able to use what I'd learned before -- as well as the code.

Curious (answer). I like word puzzles, so these all seemed interesting. For me, Puzzles (b) and (h) held a bit more interest, I suppose.

Curious (code). I like word puzzles, so these all seemed interesting. For me, Puzzles (b) and (h) held a bit more interest, I suppose.

I started off with a short file that had basic functions and a solution to Puzzle (a). Eventually, I grew an solution for all the puzzles, plus a little machinery.

Some observations:

Puzzle (a) created an interesting problem. It was easy to express a simple solution that everyone can understand immediately. But it ran s-l-o-w-l-y.


How can we make solve the puzzle more efficiently?

The problem is that the new code is much harder to write and debug. My first attempt was faster, but not fast enough. Eventually, I solved the programming puzzle by realizing that startswith() cut our search time drastically.

The final solution is much harder to understand than the simple solution. Is it worth it?

... algorithms, data structures, efficiency. Much to learn!

Other Assignments

Any questions about Exam 2? Chapters 5-7, minus a few sections, plus today's reading. Files, functions, and lists, with more problem decomposition. As you study, you can follow the same advice I gave for Exam 1.

Return Homework 9. We looked at my solution last week. Version 1 is the simplest.

Image Credits

The image of Will Shortz comes from Like me, Shortz is a native Hoosier. He once played himself on an episode of How I Met Your Mother. If that isn't cool enough, he majored in enigmatology in college.

(return to opener)

An is_happy(n) Function

The process requires repeatedly evaluating a number and finding a next number. We don't know when the process will end. That sounds like a while loop.

    while true,
      if we are done, return an answer
      compute next number

How will we know if we have seen a number before? We can store every number see in a list.

    list starts empty
    while true,
      if we are done, return an answer
      put the number in the list
      compute next number

Each of these lines is implemented in a line of Python -- except for "if we are done", because there are two ways to be done!

    numbers_seen = []                  # list starts empty
    while True:                        # while true,
        if n == 1:                     #   if we are happy,
            return True                #      return an answer
        if n in numbers_seen:          #   if we are happy,
            return False               #      return an answer
        numbers_seen.append(n)         #   put the number in the list
        n = sum_of_digits_squared(n)   #   compute next number

And there is a solution.

This works fine when testing one number. But when we call it repeatedly in a loop, as in print_happy(), it repeats the process more often than it needs to. (If we have checked 4, then we already know the answer for 37 and 42!) Can you think of a way to make our function more efficient?

I recently came across this puzzle again after many years, via The Happy Numbers Kata, by Kevin Rutherford. His blog is one of my favorites, full of good advice on programming, object-oriented design (which you will study in CS 2530), and the Ruby programming language (which is like Python).

(return to session)

Wrap Up

Eugene Wallingford ..... ..... November 18, 2014