Lab 7: Part 1. Nested For Loops

More nested loops

Create a new file called nestedLoops.py in your lab07 folder.

Task 1. Calendars

Write a function called printCalendarDays that takes a list of numbers indicating the number of days in each month, and prints a vertical calendar, with each month labeled and one day number per line. Use nested loops in your printCalendarDays function.

Examples:

printCalendarDays([5, 5, 6])

Month is 1
1
2
3
4
5

Month is 2
1
2
3
4
5

Month is 3
1
2
3
4
5
6

The input for the Gregorian calendar on a non-leap year would be:

[ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 ]

although the output is too long to be useful as a test. As another example, the 2020 Year of the Rat in the Chinese Lunar Calendar would be:

[ 29, 30, 30, 30, 29, 30, 29, 29, 30, 29, 30, 29, 30 ]

(The 1st day of the 1st month of the 2020 Chinese Lunar year falls on the 25th of January 2020 in the Gregorian calendar.)

Task 2A. Triangles

Write a function called triangle that takes one integer and prints a triangle the given height. It is possible to use string multiplication to achieve this, but if you do, consider how you could use nested loops in your triangle function instead. Think about the relationship between the number of stars in a row and the position of that row in the triangle. See comments in triangle(4) example below.

Note: In Python 3, you can change the end in print so that subsequent prints continue on the same line. (the default end with print is a newline).

for num in range(3):     
    print(5, end=" ")
print ()
print ('hello')

will print

5 5 5 
hello

Likewise:

for letter in ["A", "B", "C"]:
    print(letter, end="-")
print("done")
print("after")

will print

A-B-C-done
after

Examples:

triangle(2)
*
* *

triangle(4)
*         # 1st row, 1 star
* *       # 2nd row, 2 stars
* * *     # 3rd row, 3 stars
* * * *   # 4th row, 4 stars

triangle(7)
*
* *
* * *
* * * *
* * * * *
* * * * * *
* * * * * * *

Task 2B. Number Triangles

Write a new function called numTriangle based on your triangle function. numTriangle creates triangles are made of numbers instead of asterisks, and it is no longer possible to use string multiplication to avoid a nested loop here:

numTriangle(4)

1
1 2
1 2 3
l 2 3 4

numTriangle(7)

1
1 2
1 2 3
1 2 3 4
1 2 3 4 5
1 2 3 4 5 6
1 2 3 4 5 6 7

Task 2C. Inverted Number Triangles

Now, make a new function called invertedTriangle that prints triangles starting with the longest side and whittling down to the short side.

invertedTriangle(3)
1 2 3
1 2
1

invertedTriangle(1)
1

invertedTriangle(7)
1 2 3 4 5 6 7
1 2 3 4 5 6
1 2 3 4 5
1 2 3 4
1 2 3
1 2
1

Task 3. Dealing with 2D data

In plant ecology, a technique called quadrant sampling can be used to estimate the number of plants in a given area by counting individual plants within the cells of a square grid:

A student crouches over a quadrat taking measurements.
(image source)

The data from such a sample could be represented as a nested list (a list of lists). Which might look like this:

flowerCounts = [[4, 0, 0, 1], [1, 3, 0, 0], [0, 5, 0, 0], [1, 0, 0, 1]]

If we imagine that each inner list is a row, the list above can be seen to represent the following 2D matrix:

4 0 0 1
1 3 0 0
0 5 0 0
1 0 0 1

If we instead decided that each inner list was a column, the list above would instead represent this 2D matrix:

4 1 0 1
0 3 5 0
0 0 0 0
1 0 0 1

Although we have to make a clear decision about whether the inner lists are rows or columns, we can access data from a particular row and column by indexing twice: once to get the row (or column) and again to get the individual entry within that row (or column).

To avoid confusion, let's assume from here on out that each inner list will be a row, so we will first index by row (i.e., vertical position) and second by column (i.e., horizontal position).

Task 3A. 2D Sum

What if we just want to know the total number of plants counted anywhere in the grid? Write a function called gridSum that accepts a list of lists as an argument, and returns the sum of all numbers from each row of the grid.

Examples:

test = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
mini = [[8, 4], [23, 21]]
flowerCounts = [[4, 0, 0, 1], [1, 3, 0, 0], [0, 5, 0, 0], [1, 0, 0, 1]]
>>> gridSum(test)
45
>>> gridSum(mini)
56
>>> gridSum(flowerCounts)
16

Task 3B. Full Coverage

What if we just wanted to know whether we found at least one specimen in each grid cell? Define a function called gridNoZeroes that returns True if a grid has no zeroes in it, and False if it has at least one cell that contains a zero.

Examples:

>>> gridNoZeroes(test)
True
>>> gridNoZeroes(mini)
True
>>>gridNoZeroes(flowerCounts)
False

Task 3C. Max Cell

Which grid cell had the highest number? Let's write a function that will return a (row, column) pair indicating the location of the grid cell with the highest number (counting from 0). For example, in our test grid, the answer would be (2, 2) because the largest number is 9 in row 2 and column 2 (counting from 0 instead of 1).

Write a function called maxCell that takes a grid and returns the location of the largest element.

Examples:

>>> maxCell(test)
(2, 2)
>>> maxCell(mini)
(1, 0) # note this is 2nd row, 1st column
>>> maxCell(flowerCounts)
(2, 1) # 3rd row 2nd column

Task 4. Flatten a nested list

Write a function called flatten that takes a nested list (a list of lists) and returns a new list that has the contents of the flattened original list. Use nested loops in your flatten function.

Examples:

flatten([[0,1],[2,3,4]])
[0, 1, 2, 3, 4]

flatten([[2,4,6,8],[],[10,12]])
[2, 4, 6, 8, 10, 12]

flatten([[1,2,3],[4,5,6],[7,8]])
[1, 2, 3, 4, 5, 6, 7, 8]

flatten([[1,2,3],[4,5,6],[7,8],[9],[10]])
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

Note that flatten only flattens lists that are nested one level deep. Deeper nested lists are not flattened, as can be seen in the example below:

flatten([[1,2,[3]],[[4]]])
[1, 2, [3], [4]]

OPTIONAL Extra Tasks

Extra 1. Multiplication Charts

In the lecture notebook, you saw a function for creating multiplication tables, but it did not bother with alignment, so they were hard to read.

Write a function called multTableSpaced that prints a multiplication table, with the provided number of rows and columns, aligned so that it is easier to read. To align the columns, you just need to make sure that whenever you print a number, you print extra spaces so that shorter numbers take up up just as much space as longer numbers. It might help to write a function printSpacedNumber(num) that just takes care of that task, e.g., printSpacedNumber(7) would print ␣7, (where represents the extra space) while printSpacedNumber(12) would just print 12.

Examples:

multTableSpaced(5,6)
  1   2   3   4   5   6
  2   4   6   8  10  12
  3   6   9  12  15  18
  4   8  12  16  20  24
  5  10  15  20  25  30

multTableSpaced(5,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
  4   8  12  16  20  24  28  32  36  40
  5  10  15  20  25  30  35  40  45  50

 multTableSpaced(8,9)
  1   2   3   4   5   6   7   8   9
  2   4   6   8  10  12  14  16  18
  3   6   9  12  15  18  21  24  27
  4   8  12  16  20  24  28  32  36
  5  10  15  20  25  30  35  40  45
  6  12  18  24  30  36  42  48  54
  7  14  21  28  35  42  49  56  63
  8  16  24  32  40  48  56  64  72

Note: ideally, your multTableSpaced will work for longer numbers, as shown below. To pull this off, you will first need to figure out the width of the largest number (which will always be the result of multiplying the two largest numbers in the table). Your printSpacedNumber function will need to take two arguments: the number to print, and the width to space it to.

multTableSpaced(12,12)
  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

Extra 2A. printCalendarWeeks

Now that we've got a nice-looking multiplication table, can we do better with the formatting of our calendar (from Task 1 above)?

Write a function called printCalendarWeeks that takes a list of month lengths to print and prints a calendar where weeks are grouped in rows. Use your printSpacedNumber function from Extra 1 above to align the numbers (you can assume that the longest date in each month always has two digits).

Example:

>>> nl.printCalendarWeeks([12, 15, 23])

Month is 1
 1  2  3  4  5  6  7
 8  9 10 11 12

Month is 2
 1  2  3  4  5  6  7
 8  9 10 11 12 13 14
15

Month is 3
 1  2  3  4  5  6  7
 8  9 10 11 12 13 14
15 16 17 18 19 20 21
22 23

Extra 2B. printCalendarFancy

In a real calendar, the day numbers are aligned in columns according to the day of the week, so that the 1st day of a month isn't always in the 1st column.

Write a function called printCalendarFancy that takes a list of days-per-month, and a starting column for the 1st day of the 1st month, and prints a calendar where weeks are grouped in rows. If a week splits between months, the spacing is maintained.

Examples:

>>> printCalendarFancy([12, 15, 23], 4)

Month is 1
             1  2  3 
 4  5  6  7  8  9 10 
11 12 

Month is 2
       1  2  3  4  5 
 6  7  8  9 10 11 12 
13 14 15 

Month is 3
          1  2  3  4 
 5  6  7  8  9 10 11 
12 13 14 15 16 17 18 
19 20 21 22 23 

>>> printCalendarFancy([31, 29, 31, 30], 3) # first 4 months of 2020

Month is 1
          1  2  3  4
 5  6  7  8  9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31

Month is 2
                   1
 2  3  4  5  6  7  8
 9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29

Month is 3

 1  2  3  4  5  6  7
 8  9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31

Month is 4
          1  2  3  4
 5  6  7  8  9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30

Table of Contents