@extends('template') @section('title') Lab 7: Part 1. Nested For Loops @stop @section('head') @stop @section('content') # Lab 7: Part 1. Nested For Loops ## More nested loops Create a new file called `nestedLoops.py` in your lab07 folder. ### Task 1. `scatterStars` Write a function called `scatterStars` that takes a single integer parameter, `num` and then uses nested for loops to print `num` columns of `num` stars. Each column of stars ends with a single dash `-`. `scatterStars` is a None function. __Examples:__ ```py >>> scatterStars(2) * * - * * - >>> scatterStars(4) * * * * - * * * * - * * * * - * * * * - ``` ### Task 2. `scatterHeightStars` Write a function called `scatterHeightStars` that takes `num` and `height` integers and uses nested for loops to print `num` columns of `height` stars. Each column of stars ends with a single dash `-`. `scatterHeightStars` is a None function. __Examples:__ ```py >>> scatterHeightStars(2,5) * * * * * - * * * * * - >>> >>> scatterHeightStars(4,3) * * * - * * * - * * * - * * * - ``` ### Task 3. `scatterSpacedStars` Write a function called `scatterSpacedStars` that takes `num` and `height` integers and uses nested for loops to print `num` columns of `height` stars. Each column of stars ends with a single dash `-`. Each successive star in a given column is spaced one more space to the right than the star above it. `scatterSpacedStars` is a None function. Here is a disgram that labels the spacing of the stars: Diagraming labeling the number of
spaces in front of each star in a row. The columns of stars end up looking like slanted lines, with the topmost star in the leftmost column, and each successive star pushed one space to the right. So the bottom star ends height spaces to the right of the top star __Examples:__ ```py >>> scatterSpacedStars(2,5) * * * * * - * * * * * - ``` ```py >>> scatterSpacedStars(4,3) * * * - * * * - * * * - * * * - ``` ### Task 4. Mix and Match Write a function called `mixAndMatch` that takes two lists of strings and a verb (a string), and returns a list of sentences of the form `word1 verb word2` where `word1` is from the first list, `word2` is from the second list, and the verb is provided. __Examples:__ ```py people = ['Andy','Ada','Sohie', 'Peter'] stuff = ['python','chocolate'] bigIdeas = ['my life', 'my sleep', 'my romance'] >>> mixAndMatch(people, stuff, 'likes') ['Andy likes python', 'Andy likes chocolate', 'Ada likes python', 'Ada likes chocolate', 'Sohie likes python', 'Sohie likes chocolate', 'Peter likes python', 'Peter likes chocolate'] >>> mixAndMatch(stuff, bigIdeas, 'rules') ['python rules my life', 'python rules my sleep', 'python rules my romance', 'chocolate rules my life', 'chocolate rules my sleep', 'chocolate rules my romance'] ``` ### Task 5. Flatten a nested list Write a function called `flatten` that takes a nested list (a list of lists) and **returns** a new list that places each row into a single long list one after the other. Use nested loops in your `flatten` function. __Examples:__ ```py 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: ```py flatten([[1,2,[3]],[[4]]]) [1, 2, [3], [4]] ``` ### Task 6. distribute Write a function called `distribute(list1, list2)` that takes two lists and returns a new list of lists. There should be the same number of nested lists as there are elements in `list1`. Each nested list contains a combination of one word from `list1` and each word from `list2`, in other words, each element of `list1` should be distributed across `list2`. See below for examples. ```py >>> distribute(['a','b'],['x','y','z']) [['ax', 'ay', 'az'], ['bx', 'by', 'bz']] >>> fruit = ['banana', 'pear','apple','grape','peach','strawberry','watermelon'] >>> distribute(fruit,['NY', 'CA']) [['bananaNY', 'bananaCA'], ['pearNY', 'pearCA'], ['appleNY', 'appleCA'], ['grapeNY', 'grapeCA'], ['peachNY', 'peachCA'], ['strawberryNY', 'strawberryCA'], ['watermelonNY', 'watermelonCA']] >>> greetings = ['hola','bonjour','ciao','nihao'] >>> distribute(greetings,['ellen','portia']) [['holaellen', 'holaportia'], ['bonjourellen', 'bonjourportia'], ['ciaoellen', 'ciaoportia'], ['nihaoellen', 'nihaoportia']] ``` ### Task 7. Dealing with 2D data {{-- This part of the lab has a video walkthrough. If you get stuck or want extra context, you can watch the video below, or click the download link to download it and watch it later. The full video description on YouTube includes a breakdown of all of the topics in the video with links to each one. [Download Video](https://sakai.wellesley.edu/access/content/group/77109fc3-0650-48b0-aeb4-22c7e2e94cba/Lab%209%3A%20Nested%20Loops%20%2B%20Sorting/lab9_2D_data.mp4) | [Download Captions](https://sakai.wellesley.edu/access/content/group/77109fc3-0650-48b0-aeb4-22c7e2e94cba/Lab%209%3A%20Nested%20Loops%20%2B%20Sorting/lab9_2D_data.sbv) --}} In plant ecology, a technique called [quadrant sampling](https://www.bbc.co.uk/bitesize/guides/zmyj6sg/revision/9) 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 frame taking measurements. The frame is a wooden square with strings attached to the edges that criss-cross the interior and divide it into 16 equal-sizd squares in 4 rows and 4 columns. Placed on top of some grass that also has small flowers mixed in, each plant falls into one of the grid cells.
(image source)
The data from such a sample could be represented as a nested list (a list of lists). Which might look like this: ```py 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: ```py 4 0 0 1 1 3 0 0 0 5 0 0 1 0 0 1 ``` {{-- commenting out to streamline this lab --}} {{-- If we instead decided that each inner list was a **column**, the list above would instead represent this 2D matrix: ```py 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). --}} Each inner list, then, is a **row**, so we will **first index by row** (i.e., vertical position) and **second by column** (i.e., horizontal position). For example, `flowerCounts[2][1]` stores the value 5 (3rd row, 2nd column). #### Task 7A. 2-dimensional 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:__ ```py 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]] ``` ```py >>> gridSum(test) 45 >>> gridSum(mini) 56 >>> gridSum(flowerCounts) 16 ``` #### Task 7B. 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:__ ```py >>> gridNoZeroes(test) True >>> gridNoZeroes(mini) True >>>gridNoZeroes(flowerCounts) False ``` #### Task 7C. 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:__ ```py >>> maxCell(test) (2, 2) >>> maxCell(mini) (1, 0) # note this is 2nd row, 1st column >>> maxCell(flowerCounts) (2, 1) # 3rd row 2nd column ``` {{-- commenting out with these shortened 75 minute friday labs Term 1 --}} {{-- ## 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:__ ```py 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. ```py 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:__ ```py >>> 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:__ ```py >>> 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 ``` --}} @include('/labs/lab07/_toc') @stop