CS 110X Feb 11 2014
Expected Reading: 242-246
Expected Interactions:
Nested Loops
Split, Join
Clicker: Assessment
Captain Amazing: I knew you couldn’t change.
Casanova Frankenstein: I knew you’d know that.
Captain Amazing: Oh, I know. And I knew you’d know I’d know you knew. Casanova Frankenstein: But I didn’t. I only knew that you’d know that I knew. Did you know that? Captain Amazing: (clears throat) ... Of course.
Mystery Men
1 It is a riddle, wrapped in a mystery, inside an enigma
1.1 Left-over comments from Monday Lecture
Yesterday we discussed the implications of the following code.
>>> myList = [1, 2, 5, 10] >>> yourList = myList
It came up in the morning session (though not the afternoon) that the programmer might want to create a copy of myList to avoid this situation.
There are two ways to do so. The "clean" way (that translates to other languages) is to do something like the following:
>>> myList = [1, 2, 5, 10] >>> yourList = list(myList)
You recall how the str(...) or int(...) functions convert values from one type to another. Well, clearly those methods are responsible for returning different values than the argument passed in. In the above case, you can request to make a copy of a list by using the list(...) function.
You will also see the following Python solution to the problem, which has the following slicing syntax.
>>> myList = [1, 2, 5, 10] >>> yourList = myList[:]
If you stop and think, the slice requests ask for a list which is the subset of the list from the start to the end, which is a duplicate.
I prefer the list(...) approach, but both will work.
1.2 Nested Loops
Onward to the discussion topic for today. Nesting loops, both for and while, as well as extracting information from a file.
1.3 Simple Nesting Of Loops
write a program to print out a multiplication table for a given n.
Let’s tackle the four questions: The input is the variable n, and the output is to be printed to the console. When computing the multiplication table, you’ll need a variable to represent the "column" value, and a variable to represent the "row" value. Each line contains the n products.
Now for the overall structure, try to work out the multiplication table by yourself. You want to compute the first line, which means that the "row" value is set to 1 and the "column" value will vary from 1 to n. And once each line is completed, you advance to the next line.
The following would produce the first line of the multiplication table:
for col in range(1, n+1): line = line + str(col) + ’ ’
And the following would produce the second line of the multiplication table:
for col in range(1, n+1): line = line + str(2*col) + ’ ’
Note that the only difference is the actual product within the str(...) function call.
You have enough, now, to put down the following code fragment:
def multiplicationTable(n): line = ’’ for col in range(1, n+1): line = line + str(col) + ’ ’ print (line) line = ’’ for col in range(1, n+1): line = line + str(2*col) + ’ ’ line = ’’ for col in range(1, n+1): line = line + str(3*col) + ’ ’
The above code produces the following output:
>>> multiplicationTableRaw(10) 1 2 3 4 5 6 7 8 9 10 2 4 6 8 10 12 14 16 18 20 3 6 9 12 15 18 21 24 27 30
The values are correct, although the formatting is not desirable. However, before you continue, let’s look at the above lines one more time. The key to creating a for loop is to identify the body of statements that must be defined ONCE and then executed repeatedly within the for loop.
Clearly, the following lines are repeated, with the one difference being the actual row identifier used to compute the product. You can create a for loop as follows:
def multiplicationTable(n): for row in range(1, n+1): line = ’’ for col in range(1, n+1): line = line + str(row*col) + ’ ’ print (line)
Run this to get the following output:
1 2 3 4 5 6 7 8 9 10 11 12 2 4 6 8 10 12 14 16 18 20 22 24 3 6 9 12 15 18 21 24 27 30 33 36 4 8 12 16 20 24 28 32 36 40 44 48 5 10 15 20 25 30 35 40 45 50 55 60 6 12 18 24 30 36 42 48 54 60 66 72 7 14 21 28 35 42 49 56 63 70 77 84 8 16 24 32 40 48 56 64 72 80 88 96 9 18 27 36 45 54 63 72 81 90 99 108 10 20 30 40 50 60 70 80 90 100 110 120 11 22 33 44 55 66 77 88 99 110 121 132 12 24 36 48 60 72 84 96 108 120 132 144
Now let’s take a break and make sure we understand the variable/value assignments in this code. In-Class Exercise.
So now all that is left is to come up with a better way to format the output. One idea is to pad a product by spaces whenever it is too small. Here is my solution:
def multiplicationTable(n): for row in range(1, n+1): line = ’’ for col in range (1, n+1): product = row * col if product < 10: line = line + ’ ’ elif product < 100: line = line + ’ ’ line = line + str(product) + ’ ’ print line
Now the format is appropriate:
1 2 3 4 5 6 7 8 9 10 11 12 2 4 6 8 10 12 14 16 18 20 22 24 3 6 9 12 15 18 21 24 27 30 33 36 4 8 12 16 20 24 28 32 36 40 44 48 5 10 15 20 25 30 35 40 45 50 55 60 6 12 18 24 30 36 42 48 54 60 66 72 7 14 21 28 35 42 49 56 63 70 77 84 8 16 24 32 40 48 56 64 72 80 88 96 9 18 27 36 45 54 63 72 81 90 99 108 10 20 30 40 50 60 70 80 90 100 110 120 11 22 33 44 55 66 77 88 99 110 121 132 12 24 36 48 60 72 84 96 108 120 132 144
1.4 Another Square Nested Loop Example
Extract from a Baseball data set just the player name, homerun totals, stolen bases, and batting average. Then write this information to a file extracted.txt.
This may not immediately strike you as a nested loop, but review with the four questions:
(a) Input comes from a file; (b) variables are going to be each line of input read from the data set, the index of the corresponding columns in the data set; (c) output is going to be a file; (d) overall structure is like the "reading in from a file" code, but now we want to extract specific information from each line.
Recall that header contains:
Rk,Player,HR,Year,Age,Tm,Lg,G,PA,AB,R,H,2B,3B,RBI,BB,IBB,SO,... 1,Jose,Bautista,54,2010,29,TOR,AL,161,683,569,109,148,35,3,124,...
There is a nice capability that Python provides to construct a list from a string that has a repeated delimiter character separating values. This function is called split. Here is an example of its use.
def sampleSplit(): string = raw_input ("enter values separated by semicolons: ") myList = string.split(’;’) for element in myList: print (element)
split will create the list from the baseball data set, and you only need to know the specific index values as derived from the header.
The columns that you want are: HR (homeruns), BA (batting average), SB (stolen bases), which are columns 2, 22, and 24, respectively, in the file. Note that Player name is position 1.
def extractColumns(dataSet): inFile = open (dataSet, ’r’) outFile = open (’extracted.txt’, ’w’) for line in inFile: # new Capability: split a line by common delimiting string # into list of values entries = line.split(’,’) # somehow extract out just the required columns outFile.write(entries[1] + "," + entries[2] + "," + entries[22] + "," + entries[24]) inFile.close() outFile.close()
You can extract out the desired entries by passing into this function a list of column numbers, which match the index values of the list locations. Call this additional parameter extractColumns which hold the column indexes you want to extract. Then the inner for loop works as follows:
def extractColumns(dataSet, extractColumns): inFile = open (dataSet, ’r’) outFile = open (’extracted.txt’, ’w’) for line in inFile: # new Capability: split a line by common delimiting string # into list of values entries = line.split(’,’) # somehow extract out just the required columns for col in extractColumns: outFile.write(entries[col] + ",") outFile.write(’\n’) inFile.close() outFile.close()
Now the above will output a trailing "," with each line, but this can easily be ignored because the output still conforms to the desired output, with each extracted column present.
1.5 Triangular Nested Loops
Sometimes the inner nested loop does not execute a constant number of times (as it does with the square concepts above), but rather it increases with each pass through the loop.
For example, how would you print a triangle on the console composed solely of "+" signs? Like this:
+ +++ +++++ +++++++ +++++++++ +++++++++++ +++++++++++++ +++++++++++++++
Aside from the obvious code that simply prints out each line, one at a time, note that each line prints two more characters, and the lines are indented one fewer character each time.
See if you can work through this code example to see how it works.
def printTriangle(n): # create header of n spaces header = " " * n num = 1 while header != ’’: line = ’’ for idx in range(num): line = line + "+" print (header + line) header = header[1:] num = num + 2
1.6 Multiple Nesting Of Three Or More Loops
Here are two similar but different questions. (a) Print the list of all possible three-letter words; (b) print all three letter words that you can find using letters from the word "elephant" reading left-to-right. Thus "tan" isn’t a word, but "pat" is.
The first case is asking for a total of 263 words, but how can you print them all up? The following will do the trick.
def printAllThreeLetterWords(): letters = ’abcdefghijklmnopqrstuvwxyz’ for f in letters: for m in letters: for r in letters: print (f + m + r)
BIG QUESTION: Why can’t I just create a function printAllWords(size) where I pass in an argument for size the number of letters per word.
But what if you wanted to print all possible three letter words just using the letters from the word "elephant". The trick is you can’t reuse the same letter more than once. Thus the word "hah" doesn’t exist in "elephant" because "h" is duplicated.
First let me show you the structure and we can discuss:
def printThreeLetterWordsFromWord(word): # f iterates through first n-2 letters as first (’e’ to ’a’) # m iterates from just to the right of f to end (’l’ to ’n’) # r iterates from just to the right of m to end (’e’ to ’t’) for f in range(len(word) - 2): for m in range(f+1, len(word)-1): for r in range(m + 1, len(word)): print (word[f] + word[m] + word[r])
The first word you want to print is "ele" since these are the first three letters. Then you want to print "elp", "elh", "ela", "eln" and "elt" which completes the words that start with "el"
Note: I won’t ask you this sort of question on an exam, but you have to see this code to (a) believe it exists; and (b) have a hope of replicating it on your own.
1.7 Debug Challenge
The following code tries to write a checkboard to the screen. What is going wrong?
Press To Reveal
The above prints the following:
** ** ** ** ** ** ** **
Defects
1.8 Skills
CS-10. Understand nesting of for and while loops
1.9 Self Assessment
Given two lists, produce a multiplication table from these values
1.10 Version : 2014/02/11
(c) 2014, George Heineman