Practical programming

अब Quizwiz के साथ अपने होमवर्क और परीक्षाओं को एस करें!

16. Variables rat_1_weight and rat_2_weight contain the weights of two rats at the beginning of an experiment. Variables rat_1_rate and rat_2_rate are the rate that the rats' weights are expected to increase each week (for example, 4 percent per week). a. Using a while loop, calculate how many weeks it would take for the weight of the first rat to become 25 percent heavier than it was originally. b. Assume that the two rats have the same initial weight, but rat 1 is expected to gain weight at a faster rate than rat 2. Using a while loop, calculate how many weeks it would take for rat 1 to be 10 percent heavier than rat 2.

16. a. week = 1 while rat_1_weight[week] / rat_1_weight[0] - 1 < .25: week += 1 print(week) b. week = 0 while rat_1_weight[week] / rat_2_weight[week] - 1 < .10: week += 1 print(week)

2. Using string method count, write an expression that produces the number of o's in 'tomato'.

2. 'tomato'.count('o')

2. Repeat the previous exercise using negative indices.

2. a. kingdoms[-6] b. kingdoms[-1] c. kingdoms[-6:-3] d. kingdoms[-4:-1] e. kingdoms[-2:] f. kingdoms[-1:-2] (many other solutions)

2. For the following function calls, in what order are the subexpressions evaluated? a. min(max(3, 4), abs(-5)) b. abs(min(4, 6, max(2, 8))) c. round(max(5.572, 3.258), abs(-2))

2. a. max(3, 4), then abs(-5), then min(4, 5). b. max(2, 8), then min(4, 6, 8), then abs(4). c. max(5.572, 3.258), then abs(-2), then round(5.572, 2).

3. Rewrite the following string using single or double quotes instead of triple quotes: '''A B C'''

3. 'A\nB\nC'

3. Using string method find, write an expression that produces the index of the first occurrence of o in 'tomato'.

3. 'tomato'.find('o')

9. Consider this code: def square(num): """ (number) -> number Return the square of num. >>> square(3) 9 """ In the table below, fill in the Example column by writing square, num, square(3), and 3 next to the appropriate description. Description Example Parameter Argument Function name Function call 10. Write the body of the square function from the previous exercise.

9. Description Example Parameter num Argument 3 Function name square Function call square(3) 10. def square(num): """ (number) -> number Return the square of num. >>> square(3) 9 """ return num ** 2 ...or: def square(num): """ (number) -> number Return the square of num. >>> square(3) 9 """ return num * num

9. Print the numbers in the range 33 to 49 (inclusive).

9. for number in range(33, 50): print(number)

9. Variable season refers to 'summer'. Using string method format and variable season, write an expression that produces 'I love summer!'

9. 'I love {0}!'.format(season)

3. Write a for loop to add 1 to all the values from whales from Section 8.1, Storing and Accessing Data in Lists, on page 129, and store the converted values in a new list called more_whales. The whales list shouldn't be modified. whales refers to [5, 4, 7, 3, 2, 3, 2, 6, 4, 2, 1, 7, 1, 3].

more_whales = [] for count in whales: more_whales.append(count + 1)

1. In this exercise, you will create a table to store the population and land area of the Canadian provinces and territories according to the 2001 census. Our data is taken from http://www12.statcan.ca/english/census01/home/ index.cfm. Province/Territory Population Land Area Newfoundland and Labrador 512930 370501.69 Prince Edward Island 135294 5684.39 Nova Scotia 908007 52917.43 New Brunswick 729498 71355.67 Quebec 7237479 1357743.08 Ontario 11410046 907655.59 Manitoba 1119583 551937.87 Saskatchewan 978933 586561.35 Alberta 2974807 639987.12 British Columbia 3907738 926492.48 Yukon Territory 28674 474706.97 Northwest Territories 37360 1141108.37 Nunavut 26745 1925460.18 Table 32—2001 Canadian Census Data Write Python code that does the following: a. Creates a new database called census.db b. Makes a database table called Density that will hold the name of the province or territory (TEXT), the population (INTEGER), and the land area (REAL) c. Inserts the data from Table 32, 2001 Canadian Census Data, on page 361 d. Retrieves the contents of the table e. Retrieves the populations f. Retrieves the provinces that have populations of less than one million g. Retrieves the provinces that have populations of less than one million or greater than five million h. Retrieves the provinces that do not have populations of less than one million or greater than five million i. Retrieves the populations of provinces that have a land area greater than 200,000 square kilometers j. Retrieves the provinces along with their population densities (population divided by land area)

1. a. import sqlite3 as dbapi con = dbapi.connect('census.db') b. cur = con.cursor() cur.execute('''CREATE TABLE Density(Province TEXT, Population INTEGER, Area REAL)''') con.commit() c. table = [ ('Newfoundland and Labrador', 512930, 370501.69), ('Prince Edward Island', 135294, 5684.39), ('Nova Scotia', 908007, 52917.43), ('New Brunswick', 729498, 71355.67), ('Quebec', 7237479, 1357743.08), ('Ontario', 11410046, 907655.59), ('Manitoba', 1119583, 551937.87), ('Saskatchewan', 978933, 586561.35), ('Alberta', 2974807, 639987.12), ('British Columbia', 3907738, 926492.48), ('Yukon Territory', 28674, 474706.97), ('Northwest Territories', 37360, 1141108.37), ('Nunavut', 26745, 1925460.18), ] for row in table: cur.execute('INSERT INTO Density VALUES (?, ?, ?)', row) con.commit() d. cur.execute('SELECT * FROM Density') for row in cur.fetchall(): print(row) e. cur.execute('SELECT Population FROM Density') for row in cur.fetchall(): print(row) f. cur.execute('''SELECT Province FROM Density WHERE Population < 1000000''') for row in cur.fetchall(): print(row) g. cur.execute('''SELECT Province FROM Density WHERE Population < 1000000 OR Population > 5000000''') for row in cur.fetchall(): print(row) h. cur.execute('''SELECT Province FROM Density WHERE NOT(Population < 1000000 OR Population > 5000000)''') for row in cur.fetchall(): print(row) i. cur.execute('''SELECT Population FROM Density WHERE Area > 200000''') for row in cur.fetchall(): print(row) j. cur.execute('SELECT Province, Population / Area FROM Density') for row in cur.fetchall(): print(row)

1. Two of Python's built-in functions are min and max. In the Python shell, execute the following function calls: a. min(2, 3, 4) b. max(2, -3, 4, 7, -5) c. max(2, -3, min(4, 7), -5)

1. a. 2 a. 7 a. 4

1. What value does each of the following expressions evaluate to? Verify your answers by typing the expressions into the Python shell. a. 'Computer' + ' Science' b. 'Darwin\'s' c. 'H20' * 3 d. 'C02' * 0

1. a.'ComputerScience' b."Darwin's" c.'H2OH2OH2O' d.''

1. In the Python shell, execute the following method calls: a. 'hello'.upper() b. 'Happy Birthday!'.lower() c. 'WeeeEEEEeeeEEEEeee'.swapcase() d. 'ABC123'.isupper() e. 'aeiouAEIOU'.count('a') f. 'hello'.endswith('o') g. 'hello'.startswith('H') h. 'Hello {0}'.format('Python') i. 'Hello {0}! Hello {1}!'.format('Python', 'World')

1. a.'HELLO' b.'happy birthday!' c.'wEEEeeeeEEEeeeeEEE' d.True e.1 f.True g.False h.'Hello Python' i.'Hello Python! Hello World!'

1. All three versions of linear search start at index 0. Rewrite all three to search from the end of the list instead of from the beginning. Make sure you test them.

1. While loop version: def linear_search(lst, value): """ (list, object) -> int Return the index of the last occurrence of value in lst, or return -1 if value is not in lst. >>> linear_search([2, 5, 1, -3], 5) 1 >>> linear_search([2, 4, 2], 2) 2 >>> linear_search([2, 5, 1, -3], 4) -1 >>> linear_search([], 5) -1 """ i = len(lst) - 1 # The index of the next item in lst to examine. # Keep going until we reach the end of lst or until we find value. while i != -1 and lst[i] != value: i = i - 1 # If we fell off the end of the list, we didn't find value. if i == -1: return -1 else: return i For loop version: def linear_search(lst, value): """ (list, object) -> int Return the index of the last occurrence of value in lst, or return -1 if value is not in lst. >>> linear_search([2, 5, 1, -3], 5) 1 >>> linear_search([2, 4, 2], 2) 2 >>> linear_search([2, 5, 1, -3], 4) -1 >>> linear_search([], 5) -1 """ # The first index is included, the second is not, and the third is the # increment. for i in range(len(lst) - 1, -1, -1): if lst[i] == value: return i return -1 Sentinal version: def linear_search(lst, value): """ (list, object) -> int Return the index of the last occurrence of value in lst, or return -1 if value is not in lst. >>> linear_search([2, 5, 1, -3], 5) 1 >>> linear_search([2, 4, 2], 2) 2 >>> linear_search([2, 5, 1, -3], 4) -1 >>> linear_search([], 5) -1 """ # Add the sentinel at the beginning. lst.insert(0, value) i = len(lst) - 1 # Keep going until we find value. while lst[i] != value: i = i - 1 # Remove the sentinel. lst.pop(0) # If we reached the beginning of the list we didn't find value. if i == 0: return -1 else: # When we inserted, we shifted everything one to the right. Subtract 1 # to account for that. return i - 1

1. A DNA sequence is a string made up of the letters A, T, G, and C. To find the complement of a DNA sequence, As are replaced by Ts, Ts by As, Gs by Cs, and Cs by Gs. For example, the complement of AATTGCCGT is TTAACGGCA. a. Write an outline in English of the algorithm you would use to find the complement. b. Review your algorithm. Will any characters be changed to their complement and then changed back to their original value? If so, rewrite your outline. Hint: Convert one character at a time, rather than all of the As, Ts, Gs, or Cs at once. c. Using the algorithm that you have developed, write a function named complement that takes a DNA sequence (a str) and returns the complement of it.

1. a. Iterate over each character in the sequence from the beginning to end, replacing each A, T, G, and C with its T, A, C, and G, respectively. b. No! c. def complement(sequence): """ (str) -> str Return the complement of sequence. >>> complement('AATTGCCGT') 'TTAACGGCA' """ complement_dict = {'A': 'T', 'T': 'A', 'C': 'G', 'G': 'C'} sequence_complement = '' for char in sequence: sequence_complement = sequence_complement + complement_dict[char] return sequence_complement

1. Your lab partner claims to have written a function that replaces each value in a list with twice the preceding value (and the first value with 0). For example, if the list [1, 2, 3] is passed as an argument, the function is supposed to turn it into [0, 2, 4]. Here's the code: def double_preceding(values): """ (list of number) -> NoneType Replace each item in the list with twice the value of the preceding item, and replace the first item with 0. >>> L = [1, 2, 3] >>> double_preceding(L) >>> L [0, 2, 4] """ if values != []: temp = values[0] values[0] = 0 for i in range(1, len(values)): values[i] = 2 * temp temp = values[i] Although the example test passes, this code contains a bug. Write a set of unittest tests to identify the bug. Explain what the bug in this function is, and fix it.

1. class TestDoublePreceding(unittest.TestCase): """Tests for double_preceding.""" def test_identical(self): """Test a list with multiple identical values""" argument = [1, 1, 1] expected = [0, 2, 2] double_preceding(argument) self.assertEqual(expected, argument, "The list has multiple identical values.") The bug in the code is inside the for-loop. Instead of doubling the value of the most recently seen item in the list, it doubles the last value computed. So the result of the function is solely dependent on the first item and the length of the list. All other items are ignored. Instead, the for-loop needs to store the next value to read before overwriting it: for i in range(1, len(values)): double = 2 * temp temp = values[i] values[i] = double

1. Write a function called find_dups that takes a list of integers as its input argument and returns a set of those integers that occur two or more times in the list.

1. def find_dups(L): """ (list) -> set Return the number of duplicates numbers from L. >>> find_dups([1, 1, 2, 3, 4, 2]) {1, 2} >>> find_dups([1, 2, 3, 4]) set() """ elem_set = set() dups_set = set() for entry in L: len_initial = len(elem_set) elem_set.add(entry) len_after = len(elem_set) if len_initial == len_after: dups_set.add(entry) return(dups_set)

1. Write a program that makes a backup of a file. Your program should prompt the user for the name of the file to copy and then write a new file with the same contents but with .bak as the file extension.

1. filename = input('Which file would you like to back-up? ') new_filename = filename + '.bak' backup = open(new_filename, 'w') for line in open(filename): backup.write(line) backup.close()

1. Variable kingdoms refers to the list ['Bacteria', 'Protozoa', 'Chromista', 'Plantae', 'Fungi', 'Animalia']. Using kingdoms and either slicing or indexing with positive indices, write expressions that produce the following: a. The first item of kingdoms b. The last item of kingdoms c. The list ['Bacteria', 'Protozoa', 'Chromista'] d. The list ['Chromista', 'Plantae', 'Fungi'] e. The list ['Fungi', 'Animalia'] f. The empty list

1. a. kingdoms[0] b. kingdoms[5] c. kingdoms[:3] d. kingdoms[2:5] e. kingdoms[4:] f. kingdoms[1:0] (many other solutions)

10. In function mergesort in Mergesort, on page 262, there are two calls to extend. They are there because when the preceding loop ends, one of the two lists still has items in it that haven't been processed. Rewrite that loop so that these extend calls aren't needed.

10. There is an error in this question: it should be about function merge on page 261, not function mergesort. In order to ensure that no extend call is needed, the new version of the loop must process every element in both L1 and L2. The only way for the loop to be terminated, then, is when i1 len(L1) and i2 len(L2). We continue as long as that is not true: newL = [] i1 = 0 i2 = 0 # For each pair of items L1[i1] and L2[i2], copy the smaller into newL. while not (i1 == len(L1) and i2 == len(L2)): # append the smaller of L1[i1] and L2[i2] to newL; if one of the lists has # no items left, copy from the other one. There are now two reasons to append L1[i1] to newL: either i2 == len(L2), or both i1 and i2 are still valid and L1[i1] <= L2[i2]. In all other cases, we append L2[i2] to newL: newL = [] i1 = 0 i2 = 0 # For each pair of items L1[i1] and L2[i2], copy the smaller into newL. while not (i1 == len(L1) and i2 == len(L2)): if i2 == len(L2) or \ (i1 != len(L1) and L1[i1] <= L2[i2]): newL.append(L1[i1]) i1 += 1 else: newL.append(L2[i2]) i2 += 1 return newL

10. Write another function called db_consistent that takes a dictionary of dictionaries in the format described in the previous question and returns True if and only if every one of the inner dictionaries has exactly the same keys. (This function would return False for the previous example, since Rosalind Franklin's entry doesn't contain the 'author' key.)

10. def db_consistent(dict_of_dict): """ (dict of dict) -> set Return whether all inner dictionaries in dict_of_dict contain the same keys. >>> db_consistent({'A': {1: 'a', 2: 'b'}, 'B': {2: 'c', 3: 'd'}}) False >>> db_consistent({'A': {1: 'a', 2: 'b'}, 'B': {2: 'c', 1: 'd'}}) True """ inner_keys_list = [] # Build a list of list of keys for key in dict_of_dict: inner_keys = list(dict_of_dict[key].keys()) inner_keys.sort() inner_keys_list.append(inner_keys) for i in range(1, len(inner_keys_list)): # If the number of keys is different. if len(inner_keys_list[0]) != len(inner_keys_list[i]): return False # If the keys don't match. for j in range(len(inner_keys_list[0])): if inner_keys_list[0][j] != inner_keys_list[i][j]: return False return True

10. Print the numbers from 1 to 10 (inclusive) in descending order, all on one line.

10. for number in range(10): print(10 - number, end=' ')

10. Variables side1, side2, and side3 refer to 3, 4, and 5, respectively. Using string method format and those three variables, write an expression that produces 'The sides have lengths 3, 4, and 5.'

10. 'The sides have lengths {0}, {1}, and {2}.'.format(side1, side2, side3)

10. Variable units refers to the nested list [['km', 'miles', 'league'], ['kg', 'pound', 'stone']]. Using units and either slicing or indexing with positive indices, write expressions that produce the following: a. The first item of units (the first inner list) b. The last item of units (the last inner list) c. The string 'km' d. The string 'kg' e. The list ['miles', 'league'] f. The list ['kg', 'pound'] 11. Repeat the previous exercise using negative indices.

10. a. units[0] b. units[-1] or units[1] c. units[0][0] d. units[1][0] e. units[0][1:] f. units[1][0:2] 11. a. units[-2] b. units[-1] c. units[-2][-3] d. units[-1][-3] e. units[-2][-2:] f. units[-1][:-1]

11. Using string methods, write expressions that produce the following: a. A copy of 'boolean' capitalized b. The first occurrence of '2' in 'C02 H20' c. The second occurrence of '2' in 'C02 H20' d. True if and only if 'Boolean' begins lowercase e. A copy of "MoNDaY" converted to lowercase and then capitalized f. A copy of " Monday" with the leading whitespace removed

11. a.'boolean'.capitalize() b.'CO2 H2O'.find('2') c.'CO2 H2O'.find('2', 'CO2 H2O'.find('2') + 1) d.'Boolean'[0].islower() e."MoNDaY".lower().capitalize() f." Monday".lstrip()

11. A sparse vector is a vector whose entries are almost all zero, like [1, 0, 0, 0, 0, 0, 3, 0, 0, 0]. Storing all those zeros in a list wastes memory, so programmers often use dictionaries instead to keep track of just the nonzero entries. For example, the vector shown earlier would be represented as {0:1, 6:3}, because the vector it is meant to represent has the value 1 at index 0 and the value 3 at index 6. a. The sum of two vectors is just the element-wise sum of their elements. For example, the sum of [1, 2, 3] and [4, 5, 6] is [5, 7, 9]. Write a function called sparse_add that takes two sparse vectors stored as dictionaries and returns a new dictionary representing their sum. b. The dot product of two vectors is the sum of the products of corresponding elements. For example, the dot product of [1, 2, 3] and [4, 5, 6] is 4+10+18, or 32. Write another function called sparse_dot that calculates the dot product of two sparse vectors. c. Your boss has asked you to write a function called sparse_len that will return the length of a sparse vector (just as Python's len returns the length of a list). What do you need to ask her before you can start writing it?

11. a. def sparse_add(vector1, vector2): """ (dict of {int: int}, dict of {int: int} -> dict of {int: int}) Return the sum of sparse vectors vector1 and vector2. >>> sparse_add({1: 3, 3: 4}, {2: 4, 3: 5, 5: 6}) {1: 3, 2: 4, 3: 9, 5: 6} """ sum_vector = vector1.copy() for key in vector2: if key in sum_vector: sum_vector[key] = sum_vector[key] + vector2[key] else: sum_vector[key] = vector2[key] return sum_vector b. def sparse_dot(vector1, vector2): """ (dict of {int: int}, dict of {int: int} -> dict of {int: int}) Return the dot product of sparse vectors vector1 and vector2. >>> sparse_dot({1: 3, 3: 4}, {2: 4, 3: 5, 5: 6}) 20 """ dot = 0 for key1 in vector1: if key1 in vector2: dot = dot + vector1[key1] * vector2[key1] return dot c. Since only non-zero entries are stored, will the last entry always be non-zero? If not, how will the last entry be rep

11. Using a loop, sum the numbers in the range 2 to 22 (inclusive), and then calculate the average.

11. sum = 0 count = 0 for number in range(2,23): sum += number count += 1 average = sum / count

12. Consider this code: def remove_neg(num_list): """ (list of number) -> NoneType Remove the negative numbers from the list num_list. >>> numbers = [-5, 1, -3, 2] >>> remove_neg(numbers) >>> numbers [1, 2] """ for item in num_list: if item < 0: num_list.remove(item) When remove_neg([1, 2, 3, -3, 6, -1, -3, 1]) is executed, it produces [1, 2, 3, 6, -3, 1]. The for loop traverses the elements of the list, and when a negative value (like -3 at position 3) is reached, it is removed, shifting the subsequent values one position earlier in the list (so 6 moves into position 3). The loop then continues on to process the next item, skipping over the value that moved into the removed item's position. If there are two negative numbers in a row (like -1 and -3), then the second one won't be removed. Rewrite the code to avoid this problem.

12. def remove_neg(num_list): index = 0 while index < len(num_list): if num_list[index] < 0: del num_list[index] else: index += 1

12. Complete the examples in the docstring and then write the body of the following function: def total_occurrences(s1, s2, ch): """ (str, str, str) -> int Precondition: len(ch) == 1 Return the total number of times that ch occurs in s1 and s2. >>> total_occurrences('color', 'yellow', 'l') 3 >>> total_occurrences('red', 'blue', 'l') >>> total_occurrences('green', 'purple', 'b') """

12. def total_occurrences(s1, s2, ch): """ (str, str, str) -> int Precondition: len(ch) == 1 Return the total number of times that ch occurs in s1 and s2. >>> total_occurrences('color', 'yellow', 'l') 3 >>> total_occurrences('red', 'blue', 'l') 1 >>> total_occurrences('green', 'purple', 'b') 0 """ return s1.count(ch) + s2.count(ch)

13. Using nested for loops, print a right triangle of the character T on the screen where the triangle is one character wide at its narrowest point and seven characters wide at its widest point: T TT TTT TTTT TTTTT TTTTTT TTTTTTT

13. for width in range(1, 8): print('T' * width)

14. Using nested for loops, print the triangle described in the previous exercise with its hypotenuse on the left side: T TT TTT TTTT TTTTT TTTTTT TTTTTTT

14. for width in range(1, 8): print(' ' * (7 - width), 'T' * width, sep='')

15. Redo the previous two exercises using while loops instead of for loops.

15. width = 1 while width < 8: print('T' * width) width += 1 width = 1 while width < 8: print(' ' * (7 - width), 'T' * width, sep='') width += 1

2. Express each of the following phrases as Python strings using the appropriate type of quotation marks (single, double, or triple) and, if necessary, escape sequences. There is more than one correct answer for each of these phrases. a. They'll hibernate during the winter. b. "Absolutely not," he said. c. "He said, 'Absolutely not,'" recalled Mel. d. hydrogen sulfide e. left\right

2. a. "They'll hibernate during the winter." b. '"Absolutely not," he said.' c. '''"He said, 'Absolutely not,'" recalled Mel.''' d. 'hydrogen sulfide' e. 'left\\right'

2. Your job is to come up with tests for a function called line_intersect, which takes two lines as input and returns their intersection. More specifically: • Lines are represented as pairs of distinct points, such as [[0.0,0.0], [1.0, 3.0]] . • If the lines don't intersect, line_intersect returns None. • If the lines intersect in one point, line_intersect returns the point of intersection, such as [0.5, 0.75]. • If the lines are coincident (that is, lie on top of each other), the function returns its first argument (that is, a line). What are the six most informative test cases you can think of? (That is, if you were allowed to run only six tests, which would tell you the most about whether the function was implemented correctly?) Write out the inputs and expected outputs of these six tests, and explain why you would choose them.

2. >>> line_intersect([[-1, -1], [1, 1]], [[-1, 1], [1, -1]]) [0, 0] The arguments intersect so we expect to get their point of intersection. >>> line_intersect([[0, 0], [0, 0]], [[0, 0], [0, 1]]) None The first argument is not a pair of distinct points so they can't intersect. >>> line_intersect([[0, 0], [0, 1]], [[0, 0], [0, 0]]) None The second argument is not a pair of distinct points so they can't intersect. >>> line_intersect([[0, 0], [1, 0]], [[0, 0], [2, 0]]) [[0, 0], [1, 0]] The lines are coincident so we expect the first line as the return value. >>> line_intersect([[0, 0], [2, 0]], [[0, 0], [1, 0]]) [[0, 0], [2, 0]] Same as the previous, but we switch the order. We still expect the first line as the return value. >>> line_intersect([[0, 0], [1, 0]], [[0, 1], [1, 1]]) None The lines are parallel but not coincident, so they don't intersect. This ensures we detect coincident lines properly.

2. For the new versions of linear search: if there are duplicate values, which do they find?

2. If there are duplicates, the one at the highest index is found.

2. In this exercise, you'll develop a function that finds the minimum or maximum value in a list, depending on the caller's request. a. Write a loop (including initialization) to find both the minimum value in a list and that value's index in one pass through the list. b. Write a function named min_index that takes one parameter (a list) and returns a tuple containing the minimum value in the list and that value's index in the list. c. You might also want to find the maximum value and its index. Write a function named min_or_max_index that has two parameters: a list and a bool. If the Boolean parameter refers to True, the function returns a tuple containing the minimum and its index; and if it refers to False, it returns a tuple containing the maximum and its index.

2. a. index = 0 smallest = L[0] for i in range(1, len(L)): if L[i] < smallest: index = i smallest = L[i] b. def min_index(L): """ (list) -> (object, int) Return a tuple containing the smallest item from L and its index. >>> min_index([4, 3, 2, 4, 3, 6, 1, 5]) (1, 6) """ index = 0 smallest = L[0] for i in range(1, len(L)): if L[i] < smallest: index = i smallest = L[i] return (smallest, index) c. def min_or_max_index(L, flag): """ (list, bool) -> tuple of (object, int) Return the minimum or maximum item and its index from L, depending on whether flag is True or False. >>> min_or_max_index([4, 3, 2, 4, 3, 6, 1, 5], True) (1, 6) >>> min_or_max_index([4, 3, 2, 4, 3, 6, 1, 5], False) (6, 5) """ index = 0 current_value = L[0] if flag: for i in range(1, len(L)): if L[i] < current_value: index = i current_value = L[i] else: for i in range(1, len(L)): if L[i] > current_value: index = i current_value = L[i] return (current_value, index)

2. Suppose the file alkaline_metals.txt contains the name, atomic number, and atomic weight of the alkaline earth metals: beryllium 4 9.012 magnesium 12 24.305 calcium 20 20.078 strontium 38 87.62 barium 56 137.327 radium 88 226 Write a for loop to read the contents of alkaline_metals.txt and store it in a list of lists, with each inner list containing the name, atomic number, and atomic weight for an element. (Hint: Use string.split.)

2. alkaline_metals = [] for line in open('alkaline_metals.txt'): alkaline_metals.append(line.strip().split(' '))

2. Python's set objects have a method called pop that removes and returns an arbitrary element from the set. If the set gerbils contains five cuddly little animals, for example, calling gerbils.pop() five times will return those animals one by one, leaving the set empty at the end. Use this to write a function called mating_pairs that takes two equal-sized sets called males and females as input and returns a set of pairs; each pair must be a tuple containing one male and one female. (The elements of males and females may be strings containing gerbil names or gerbil ID numbers—your function must work with both.)

2. def mating_pairs(males, females): """ (set, set) -> set of tuple Return a set of tuples where each tuple contains a male from males and a female from females. >>> mating_pairs({'Anne', 'Beatrice', 'Cari'}, {'Ali', 'Bob', 'Chen'}) {('Cari', 'Chen'), ('Beatrice', 'Bob'), ('Anne', 'Ali')} """ pairs = set() num_gerbils = len(males) for i in range(num_gerbils): male = males.pop() female = females.pop() pairs.add((male, female),) return pairs

2. For this exercise, add a new table called Capitals to the database. Capitals has three columns—province/territory (TEXT), capital (TEXT), and population (INTEGER)—and it holds the data shown here: Province/Territory Capital Population Newfoundland and Labrador St. John's 172918 Prince Edward Island Charlottetown 58358 Nova Scotia Halifax 359183 New Brunswick Fredericton 81346 Quebec Quebec City 682757 Ontario Toronto 4682897 Manitoba Winnipeg 671274 Saskatchewan Regina 192800 Alberta Edmonton 937845 British Columbia Victoria 311902 Yukon Territory Whitehorse 21405 Northwest Territories Yellowknife 16541 Nunavut Iqaluit 5236 Table 33—2001 Canadian Census Data: Capital City Populations Write SQL queries that do the following: a. Retrieve the contents of the table b. Retrieve the populations of the provinces and capitals (in a list of tuples of the form [province population, capital population]) c. Retrieve the land area of the provinces whose capitals have populations greater than 100,000 d. Retrieve the provinces with land densities less than two people per square kilometer and capital city populations more than 500,000 e. Retrieve the total land area of Canada f. Retrieve the average capital city population g. Retrieve the lowest capital city population h. Retrieve the highest province/territory population i. Retrieve the provinces that have land densities within 0.5 persons per square kilometer of on another—have each pair of provinces reported only once

2. import sqlite3 as dbapi con = dbapi.connect('census.db') cur = con.cursor() cur.execute('''CREATE TABLE Capitals(Province TEXT, Capital TEXT, Population INTEGER)''') con.commit() table = [ ('Newfoundland and Labrador', "St. John's", 172918), ('Prince Edward Island', 'Charlottetown', 58358), ('Nova Scotia', 'Halifax', 359183), ('New Brunswick', 'Fredericton', 81346), ('Quebec', 'Qeubec City', 682757), ('Ontario', 'Toronto', 4682897), ('Manitoba', 'Winnipeg', 671274), ('Saskatchewan', 'Regina', 192800), ('Alberta', 'Edmonton', 937845), ('British Columbia', 'Victoria', 311902), ('Yukon Territory', 'Whitehorse', 21405), ('Northwest Territories', 'Yellowknife', 16541), ('Nunavut', 'Iqaluit', 5236), ] for row in table: cur.execute('INSERT INTO Capitals VALUES (?, ?, ?)', row) con.commit() a. cur.execute('SELECT * FROM Capitals') for row in cur.fetchall(): print(row) b. cur.execute('''SELECT Density.Population, Capitals.Population FROM Capitals INNER JOIN Density WHERE Capitals.Province = Density.Province''') for row in cur.fetchall(): print(row) c. cur.execute('''SELECT Density.Area FROM Capitals INNER JOIN Density WHERE Capitals.Province = Density.Province AND Capitals.Population > 100000''') for row in cur.fetchall(): print(row) d. Note: This query doesn't return any results. cur.execute('''SELECT Density.Province FROM Capitals INNER JOIN Density WHERE Capitals.Province = Density.Province AND Density.Population / Density.Area < 2 AND Capitals.Population > 500000''') for row in cur.fetchall(): print(row) e. cur.execute('SELECT SUM(Area) FROM Density') print(cur.fetchone()) f. cur.execute('SELECT AVG(Population) FROM Capitals') print(cur.fetchone()) g. cur.execute('SELECT MIN(Population) FROM Capitals') print(cur.fetchone()) h. cur.execute('SELECT MAX(Population) FROM Density') print(cur.fetchone()) i. cur.execute('''SELECT A.Province, B.Province FROM Density A INNER JOIN Density B WHERE A.Province < B.Province AND ABS(A.Population / A.Area - B.Population / B.Area) < 0.5''') for row in cur.fetchall(): print(row)

3. Binary search is significantly faster than the built-in search but requires that the list is sorted. As you know, the running time for the best sorting algorithm is on the order of N log2 N, where N is the length of the list. If we search a lot of times on the same list of data, it makes sense to sort it once before doing the searching. Roughly how many times do we need to search in order to make sorting and then searching faster than using the built-in search?

3. The question asks roughly how many times we need to search in order to make sorting the list first (on the order of N log_2 N steps) and then using binary search (on the order of log_2 N steps) faster than than just using linear search (on the order of N steps). If there are k searches, then using linear search takes on the order of k * N steps. It takes N log_2 N steps to sort a list with N items. In addition to the sorting time, there are all the binary searches to account for, each taking log_2 N steps, so this approach takes on the order of N log_2 N + k * N log_2 N steps. N log_2 N + k * log_2 N < k * N [subtract k * log_2 N from both sides] N log_2 N < k * N - k * log_2 N [simplify] N log_2 N < k * (N - log_2 N) [divide both sides by (N - log_2 N)] (N log_2 N) / (N - log_2 N) < k [N is much larger than log_2 N, so we simplify the denominator and multiply the numerator by 2 (remember, we want a rough answer)] (2 * N log_2 N) / N < k [simplify] 2 * log_2 N < k The actual threshold is slightly smaller, but this is a fine rough estimate.

3. All of the file-reading functions we have seen in this chapter read forward through the file from the first character or line to the last. How could you write a function that would read backward through a file?

3. We could read the file contents into a data structure, such as a list, and then iterate over the list from end (last line) to beginning (first line).

3. In The Readline Technique, on page 179, you learned how to read some files from the Time Series Data Library. In particular, you learned about the Hopedale data set, which describes the number of colored fox fur pelts produced from 1834 to 1842. This file contains one value per year per line. a. Write an outline in English of the algorithm you would use to read the values from this data set to compute the average number of pelts produced per year. b. Translate your algorithm into Python by writing a function named hopedale_average that takes a filename as a parameter and returns the average number of pelts produced per year.

3. a. - Read the description line. - Keep reading the comment lines until we read the first piece of data. - Add the first piece of data to an empty list. - Read the remaining lines one at a time, appending the data to the list. b. def hopedale_average(filename): """ (str) -> float Return the average number of pelts produced per year for the data in Hopedale file named filename. """ with open(filename, 'r') as hopedale_file: # Read the description line. hopedale_file.readline() # Keep reading comment lines until we read the first piece of data. data = hopedale_file.readline().strip() while data.startswith('#'): data = hopedale_file.readline().strip() # Now we have the first piece of data append it to an empty list. pelts_list = [] pelts_list.append(int(data)) # Read the rest of the data. for data in hopedale_file: pelts_list.append(int(data.strip())) return sum(pelts_list) / len(pelts_list)

3. Using unittest, write four tests for a function called all_prefixes in a module called TestPrefixes.py that takes a string as its input and returns the set of all nonempty substrings that start with the first character. For example, given the string "lead" as input, all_prefixes would return the set {"l", "le", "lea", "lead"}.

3. class TestAllPrefixes(unittest.TestCase): """Tests for all_prefixes.""" def test_empty(self): """Test the empty string.""" argument = all_prefixes('') expected = set() self.assertEqual(expected, argument, 'Argument is empty string.') def test_single_letter(self): """Test a one-character string.""" argument = all_prefixes('x') expected = {'x'} self.assertEqual(expected, argument, 'Argument is single letter.') def test_word(self): """Test a word with unique letters.""" argument = all_prefixes('water') expected = {'w', 'wa', 'wat', 'wate', 'water'} self.assertEqual(expected, argument, 'Argument is word with unique letters.') def test_multiple(self): """Test a word with multiple occurences of the first letter.""" argument = all_prefixes('puppet') expected = {'p', 'pu', 'pup', 'pupp', 'puppe', 'puppet', 'pp', 'ppe', 'ppet', 'pe', 'pet'} self.assertEqual(expected, argument, 'First letter occurs multiple times')

3. The PDB file format is often used to store information about molecules. A PDB file may contain zero or more lines that begin with the word AUTHOR (which may be in uppercase, lowercase, or mixed case), followed by spaces or tabs, followed by the name of the person who created the file. Write a function that takes a list of filenames as an input argument and returns the set of all author names found in those files.

3. def get_authors(filenames): """ (list of str) -> set of str Return a list of the authors in PDB files names appear in filenames. """ authors = set() for filename in filenames: pdb_file = open(filename) for line in pdb_file: if line.lower().startswith('author'): author = line[6:].strip() authors.add(author) return authors

3. Following the function design recipe, define a function that has one parameter, a number, and returns that number tripled.

3. def triple(num): """ (number) -> number Return num tripled. >>> triple(3) 9 """ return num * 3

3. Write a Python program that creates a new database and executes the following SQL statements. How do the results of the SELECT statements differ from what you would expect Python itself to do? Why? CREATE TABLE Numbers(Val INTEGER) INSERT INTO Numbers Values(1) INSERT INTO Numbers Values(2) SELECT * FROM Numbers WHERE 1/0 SELECT * FROM Numbers WHERE 1/0 AND Val > 0 SELECT * FROM Numbers WHERE Val > 0 AND 1/0

3. In Python, division by zero results in an error being thrown: >>> value = 1 >>> 1/0 Traceback (most recent call last): File "<stdin>", line 1, in <module> ZeroDivisionError: division by zero >>> 1/0 and value > 0 Traceback (most recent call last): File "<stdin>", line 1, in <module> ZeroDivisionError: division by zero >>> value > 0 and 1/0 Traceback (most recent call last): File "<stdin>", line 1, in <module> ZeroDivisionError: division by zero In SQL, division by zero results in a special value that represents infinity (if the numerator is not zero) or "not a number" when the numerator is zero. However, even though this special value is non-zero it does not evaluate to True. So in each select statement, no rows are returned.

3. Variable appointments refers to the list ['9:00', '10:30', '14:00', '15:00', '15:30']. An appointment is scheduled for 16:30, so '16:30' needs to be added to the list. a. Using list method append, add '16:30' to the end of the list that appointments refers to. b. Instead of using append, use the + operator to add '16:30' to the end of the list that appointments refers to. c. You used two approaches to add '16:30' to the list. Which approach modified the list and which approach created a new list?

3. a. appointments.append('16:30') b. appointments += ['16:30'] c. The approach in (a) modifies the list. The one in (b) creates a new list.

4. Write a set of doctests for the find-two-smallest functions. Think about what kinds of data are interesting, long lists or short lists, and what order the items are in. Here is one list to test with: [1, 2]. What other interesting ones are there?

4. # Two items; smallest first. >>> find_two_smallest([1, 2]) (0, 1) # Two items; smallest second. >>> find_two_smallest([3, 2]) (1, 0) # Two items; same values. >>> find_two_smallest([3, 3]) (0, 1) # Three items items; 2nd smallest is duplicated. >>> find_two_smallest([3, 1, 3]) (1, 0) # Multiple items: smallest at beginning; 2nd smallest at middle. >>> find_two_smallest([1, 4, 2, 3, 4]) (0, 2) # Multiple items: smallest at middle; 2nd smallest at end. >>> find_two_smallest([4, 3, 1, 5, 6, 2]) (5, 3) # Multiple items: smallest at end; 2nd smallest at beginning. >>> find_two_smallest([-2, 4, 3, 2, 5, 6, -1]) (3, 4)

4. Use built-in function len to find the length of the empty string.

4. >>> len('') 0

4. Given the unsorted list [6, 5, 4, 3, 7, 1, 2], show what the contents of the list would be after each iteration of the loop as it is sorted using the following: a. Selection sort b. Insertion sort

4. a. Selection sort: [6, 5, 4, 3, 7, 1, 2] [1, 5, 4, 3, 7, 6, 2] [1, 2, 4, 3, 7, 6, 5] [1, 2, 3, 4, 7, 6, 5] [1, 2, 3, 4, 5, 6, 7] # Because selection sort doesn't stop even though the list is sorted, # there is one more iteration. [1, 2, 3, 4, 5, 6, 7] b. Insertion sort: [6, 5, 4, 3, 7, 1, 2] [5, 6, 4, 3, 7, 1, 2] [4, 5, 6, 3, 7, 1, 2] [3, 4, 5, 6, 7, 1, 2] [3, 4, 5, 6, 7, 1, 2] # The 7 doesn't move on this iteration. [1, 3, 4, 5, 6, 7, 2] [1, 2, 3, 4, 5, 6, 7]

4. Using unittest, write the five most informative tests you can think of for a function called is_sorted in a module called TestSorting.py that takes a list of integers as input and returns True if they are sorted in nondecreasing order (as opposed to strictly increasing order, because of the possibility of duplicate values), and False otherwise

4. class TestSorting(unittest.TestCase): """Tests for is_sorted.""" def test_empty(self): """Test an empty list.""" argument = is_sorted([]) expected = True self.assertEqual(expected, argument, "The list is empty.") def test_one_item(self): """Test a list with one item.""" argument = is_sorted([1]) expected = True self.assertEqual(expected, argument, "The list has one item.") def test_duplicates(self): """Test a sorted list with duplicate values.""" argument = is_sorted([1, 2, 2, 3]) expected = True self.assertEqual(expected, argument, "The list has duplicate values.") def test_not_sorted(self): """Test an unsorted list.""" argument = is_sorted([3, 2]) expected = False self.assertEqual(expected, argument, "The list has one item.")

4. Following the function design recipe, define a function that has two parameters, both of which are numbers, and returns the absolute value of the difference of the two. Hint: Call built-in function abs.

4. def absolute_difference(number1, number2): """ (number, number) -> number Return the absolute value of the difference between number1 and number2. >>> absolute_difference(3, 7) 4 """ return abs(number1 - number2)

4. The keys in a dictionary are guaranteed to be unique, but the values are not. Write a function called count_values that takes a single dictionary as an argument and returns the number of distinct values it contains. Given the input {'red': 1, 'green': 1, 'blue': 2}, for example, it should return 2.

4. def count_values(dictionary): """ (dict) -> int Return the number of unique values in dictionary. >>> count_values({'red': 1, 'green': 2, 'blue': 2}) 2 """ return len(set(dictionary.values()))

4. In Processing Whitespace-Delimited Data, on page 187, we used the "For Line in File" technique to process data line by line, breaking it into pieces using string method split. Rewrite function process_file to skip the header as normal but then use the Read technique to read all the data at once.

4. def process_file(reader): """ (file open for reading) -> NoneType Read and print the data from reader, which must start with a single description line, then a sequence of lines beginning with '#', then a sequence of data. """ # Find and print the first piece of data. line = skip_header(reader).strip() print(line) # Read the rest of the data. print(reader.read())

4. Using string method find, write a single expression that produces the index of the second occurrence of o in 'tomato'. Hint: Call find twice.

4. 'tomato'.find('o', 'tomato'.find('o') + 1)

4. Variable ids refers to the list [4353, 2314, 2956, 3382, 9362, 3900]. Using list methods, do the following: a. Remove 3382 from the list. b. Get the index of 9362. c. Insert 4499 in the list after 9362. d. Extend the list by adding [5566, 1830] to it. e. Reverse the list. f. Sort the list.

4. a. ids.remove(3382) b. ids.index(9362) c. ids.insert(ids.index(9362) + 1, 4499) d. ids = ids + [5566, 1830] or:

5. Given variables x and y, which refer to values 3 and 12.5, respectively, use function print to print the following messages. When numbers appear in the messages, variables x and y should be used. a. The rabbit is 3. b. The rabbit is 3 years old. c. 12.5 is average. d. 12.5 * 3 e. 12.5 * 3 is 37.5.

5. a. print('The rabbbit is ' + str(x) + '.') b. print('The rabbbit is', x, 'years old.') a. print(y, 'is average.') a. print(y, '*', x) a. print(str(y) + ' * ' + str(x) + ' is ' + str(y * x) + '.')

5. What happens if the functions to find the two smallest values in a list are passed a list of length one? What should happen, and why? How about length zero? Modify one of the docstrings to describe what happens.

5. If passed a list of length one, it should return a tuple containing the index of the smallest. If passed a list of length zero, it should return an empty tuple. Return a tuple of the indices of the two smallest values in list L. If there is only one item in L or zero items in L, return a tuple containing the index of that one item or an empty tuple, respectively.

5. The following function is broken. The docstring describes what it's supposed to do: def find_min_max(values): """ (list) -> NoneType Print the minimum and maximum value from values. """ min = None max = None for value in values: if value > max: max = value if value < min: min = value print('The minimum value is {0}'.format(min)) print('The maximum value is {0}'.format(max)) What does it actually do? What line(s) do you need to change to fix it?

5. The first time the if-blocks in the for-loop are executed, the value is compared with None. Since such comparisons aren't allowed in Python, the code throws an Error. To fix it, you'll need to change the for-loop to this: for value in values: if max is None or value > max: max = value if min is None or value < min: min = value

5. Another sorting algorithm is bubble sort. Bubble sort involves keeping a sorted section at the end of the list. The list is traversed, pairs of elements are compared, and larger elements are swapped into the higher position. This is repeated until all elements are sorted. a. Using the English description of bubble sort, write an outline of the bubble sort algorithm in English. b. Continue using top-down design until you have a Python algorithm. c. Turn it into a function called bubble_sort(L). d. Try it out on the test cases from selection_sort.

5. a. until all items are sorted: # sweep through the list. for each pair of items in the unsorted part of the list: if the pair is out of order: swap them b. After the first sweep, the largest item must have been swapped to the end of the list. After the second sweep, the second-largest item must have been swapped to the second-last spot. So there is a sorted section accumulating at the end of the list, and we'll keep track of the end of the unsorted section. # The end of the unsorted section. The largest item will be placed here. end = len(lst) - 1 # Keep going until there is only one item to consider. while end != 0: # sweep through the list. for each pair of items in the unsorted part of the list: if the pair is out of order: swap them end = end - 1 Now we consider "for each pair of items in the unsorted part of the list". Here, we compare each item to the one that follows it. The last pair we compare is lst[end - 1] and lst[end]. # The end of the unsorted section. The largest item will be placed here. end = len(lst) - 1 # Keep going until there is only one item to consider. while end != 0: # sweep through the list. for i in range(0, end): if lst[i - 1] > lst[i]: swap them end = end - 1 Swapping is straightforward: # The end of the unsorted section. The largest item will be placed here. end = len(lst) - 1 # Keep going until there are either 0 or 1 items to consider. # (The 0 case is for the empty list.) while end > 0: # sweep through the list. for i in range(0, end): if lst[i] > lst[i + 1]: tmp = lst[i + 1] lst[i + 1] = lst[i] lst[i] = tmp end = end - 1 c and d. (using doctest) def bubble_sort(lst): """ (list) -> NoneType Reorder the items in L from smallest to largest. >>> L = [3, 4, 7, -1, 2, 5] >>> bubble_sort(L) >>> L [-1, 2, 3, 4, 5, 7] >>> L = [] >>> bubble_sort(L) >>> L [] >>> L = [1] >>> bubble_sort(L) >>> L [1] >>> L = [2, 1] >>> bubble_sort(L) >>> L [1, 2] >>> L = [1, 2] >>> bubble_sort(L) >>> L [1, 2] >>> L = [3, 3, 3] >>> bubble_sort(L) >>> L [3, 3, 3] >>> L = [-5, 3, 0, 3, -6, 2, 1, 1] >>> bubble_sort(L) >>> L [-6, -5, 0, 1, 1, 2, 3, 3] """ # The end of the unsorted section. The largest item will be placed here. end = len(lst) - 1 # Keep going until there are either 0 or 1 items to consider. # (The 0 case is for the empty list.) while end > 0: # sweep through the list. for i in range(0, end): if lst[i] > lst[i + 1]: tmp = lst[i + 1] lst[i + 1] = lst[i] lst[i] = tmp end = end - 1

5. After doing a series of experiments, you have compiled a dictionary showing the probability of detecting certain kinds of subatomic particles. The particles' names are the dictionary's keys, and the probabilities are the values: {'neutron': 0.55, 'proton': 0.21, 'meson': 0.03, 'muon': 0.07, 'neutrino': 0.14}. Write a function that takes a single dictionary of this kind as input and returns the particle that is least likely to be observed. Given the dictionary shown earlier, for example, the function would return 'meson'.

5. def least_likely(particle_to_probability): """ (dict of {str: float}) -> str Return the particle from particle_to_probability with the lowest probablity. >>> least_likely({'neutron': 0.55, 'proton': 0.21, 'meson': 0.03, 'muon': 0.07}) 'meson' """ smallest = 1 name = '' for particle in particle_to_probability: probability = particle_to_probability[particle] if probability < smallest: smallest = probability name = particle return particle

5. The following function doesn't have a docstring or comments. Write enough of both to make it easy for another programmer to understand what the function does and how, and then compare your solution with those of at least two other people. How similar are they? Why do they differ? def mystery_function(values): result = [] for sublist in values: result.append([sublist[0]]) for i in sublist[1:]: result[-1].insert(0, i) return result

5. def mystery_function(values): """ (list) -> list Return a copy of the list, values, and the sublists it contains. The top-level sublists have their elements reversed in the returned list. >>> mystery_function([[1, 2, 3], [4, 5, 6]]) [[3, 2, 1], [6, 5, 4]] """ result = [] for sublist in values: # Copy the sublist in reverse order by inserting each # element to the front of the new sublist. result.append([sublist[0]]) for i in sublist[1:]: result[-1].insert(0, i) return result

5. Modify the file reader in read_smallest_skip.py of Skipping the Header, on page 183, so that it can handle files with no data after the header.

5. import time_series def smallest_value_skip(reader): """ (file open for reading) -> number or NoneType Read and process reader, which must start with a time_series header. Return the smallest value after the header. Skip missing values, which are indicated with a hyphen. """ line = time_series.skip_header(reader).strip() # Only execute this code, if there is data following the header. if line != '': smallest = int(line) for line in reader: line = line.strip() if line != '-': value = int(line) smallest = min(smallest, value) return smallest if __name__ == '__main__': with open('hebron.txt', 'r') as input_file: print(smallest_value_skip(input_file))

5. Following the function design recipe, define a function that has one parameter, a distance in kilometers, and returns the distance in miles. (There are 1.6 kilometers per mile.)

5. def km_to_miles(km): """ (number) -> float Return the distance km in miles. >>> km_to_miles(5) 3.125 """ return km / 1.6

5. Using your expression from the previous exercise, find the second o in 'avocado'. If you don't get the result you expect, revise the expression and try again.

5. 'avocado'.find('o', 'avocado'.find('o') + 1)

5. In this exercise, you'll create a list and then answer questions about that list. a. Assign a list that contains the atomic numbers of the six alkaline earth metals—beryllium (4), magnesium (12), calcium (20), strontium (38), barium (56), and radium (88)—to a variable called alkaline_earth_metals. b. Which index contains radium's atomic number? Write the answer in two ways, one using a positive index and one using a negative index. c. Which function tells you how many items there are in alkaline_earth_metals? d. Write code that returns the highest atomic number in alkaline_earth_metals. (Hint: Use one of the functions from Table 9, List Functions, on page 134.)

5. a. alkaline_earth_metals = [4, 12, 20, 38, 56, 88] b. alkaline_earth_metals[5], alkaline_earth_metals[-1] c. len(alkaline_earth_metals) d. max(alkaline_earth_metals)

6. Suppose you have a data set of survey results where respondents can optionally give their age. Missing values are read in as None. Here is a function that computes the average age from that list. def average(values): """ (list of number) -> number Return the average of the numbers in values. Some items in values are None, and they are not counted toward the average. >>> average([20, 30]) 25.0 >>> average([None, 20, 30]) 25.0 """ count = 0 # The number of values seen so far. total = 0 # The sum of the values seen so far. for value in values: if value is not None: total += value count += 1 return total / count Unfortunately it does not work as expected: >>> import test_average >>> test_average.average([None, 30, 20]) 16.666666666666668 a. Using unittest, write a set of tests for function average in a module called test_average.py. The tests should cover cases involving lists with and without missing values. b. Modify function average so it correctly handles missing values and passes all of your tests.

6. a. class TestAverage(unittest.TestCase): """Tests for average.""" def test_empty(self): """Test an empty list.""" argument = average([]) expected = None self.assertEqual(expected, argument, "The list is empty.") def test_one_item(self): """Test a list with one item.""" argument = average([5]) expected = 5 self.assertEqual(expected, argument, "The list has one item.") def test_one_none(self): """Test a list with one 'None'.""" argument = average("None":http://pragprog.com/wikis/wiki/None) expected = None self.assertEqual(expected, argument, "The list has one 'None'.") def test_normal(self): """Test a list with multiple numbers.""" argument = average([1, 2, 3]) expected = 2 self.assertEqual(expected, argument, "The list has multiple numbers.") def test_normal_with_none(self): """Test a list with multiple numbers and one 'None'.""" argument = average("1, 2, 3":http://pragprog.com/wikis/wiki/None,) expected = 2 self.assertEqual(expected, argument, "The list has multiple numbers and one 'None'.") b. def average(values): """ (list of number) -> number Return the average of the numbers in values. Some items in values are None, and they are not counted toward the average. >>> average([20, 30]) 25.0 >>> average("20, 30":http://pragprog.com/wikis/wiki/None,) 25.0 """ count = 0 # The number of values seen so far. total = 0 # The sum of the values seen so far. for value in values: if value is not None: total += value count += 1 if count == 0: return None return total / count

6. In the description of bubble sort in the previous exercise, the sorted section of the list was at the end of the list. In this exercise, bubble sort will maintain the sorted section at the beginning of the list. Make sure that you are still implementing bubble sort! a. Rewrite the English description of bubble sort from the previous exercise with the necessary changes so that the sorted elements are at the beginning of the list instead of at the end. b. Using your English description of bubble sort, write an outline of the bubble sort algorithm in English. c. Write function bubble_sort_2(L). d. Try it out on the test cases from selection_sort.

6. a. until all items are sorted: # sweep through the list from the end to the beginning. for each pair of items in the unsorted part of the list: if the pair is out of order: swap them b. After the first sweep, the largest item must have been swapped to the front of the list. After the second sweep, the second-largest item must have been swapped to the second spot. So there is a sorted section accumulating at the front of the list, and we'll keep track of the beginning of the unsorted section. # The beginning of the unsorted section. The next-smallest item will be placed here. beginning = 0 # Keep going until there is only one item to consider. while beginning < len(lst): # sweep through the list from the beginning to the front. for each pair of items in the unsorted part of the list: if the pair is out of order: swap them beginning = beginning + 1 Now we consider "for each pair of items in the unsorted part of the list". Here, we compare each item to the one that precedes it. The last pair we compare is lst[beginning + 1] and lst[beginning]. # The beginning of the unsorted section. The largest item will be placed here. beginning = 0 # Keep going until there is only one item to consider. while beginning < len(lst): # sweep through the list. for i in range(len(lst) - 1, beginning, -1): if lst[i] < lst[i - 1]: swap them beginning = beginning + 1 Swapping is straightforward: # The beginning of the unsorted section. The largest item will be placed here. beginning = 0 # Keep going until there is only one item to consider. while beginning < len(lst): # sweep through the list. for i in range(len(lst) - 1, beginning, -1): if lst[i] < lst[i - 1]: tmp = lst[i - 1] lst[i - 1] = lst[i] lst[i] = tmp beginning = beginning + 1 c and d. (using doctest) def bubble_sort(lst): """ (list) -> NoneType Reorder the items in L from smallest to largest. >>> L = [3, 4, 7, -1, 2, 5] >>> bubble_sort(L) >>> L [-1, 2, 3, 4, 5, 7] >>> L = [] >>> bubble_sort(L) >>> L [] >>> L = [1] >>> bubble_sort(L) >>> L [1] >>> L = [2, 1] >>> bubble_sort(L) >>> L [1, 2] >>> L = [1, 2] >>> bubble_sort(L) >>> L [1, 2] >>> L = [3, 3, 3] >>> bubble_sort(L) >>> L [3, 3, 3] >>> L = [-5, 3, 0, 3, -6, 2, 1, 1] >>> bubble_sort(L) >>> L [-6, -5, 0, 1, 1, 2, 3, 3] """ # The beginning of the unsorted section. The largest item will be placed # here. beginning = 0 # Keep going until there is only one item to consider. while beginning < len(lst): # sweep through the list. for i in range(len(lst) - 1, beginning, -1): if lst[i] < lst[i - 1]: tmp = lst[i - 1] lst[i - 1] = lst[i] lst[i] = tmp beginning = beginning + 1

6. Following the function design recipe, define a function that has three parameters, grades between 0 and 100 inclusive, and returns the average of those grades.

6. def average_grade(grade1, grade2, grade3): """ (number, number, number) -> number Return the average of the grade1, grade2, and grade3, where each grade ranges from 0 to 100, inclusive. >>> average_grade(80, 95, 90) 88.33333333333333 """ return (grade1 + grade2 + grade3) / 3

6. Write a function called count_duplicates that takes a dictionary as an argument and returns the number of values that appear two or more times.

6. def count_duplicates(dictionary): """ (dic) -> int Return the number of duplicate values in dictionary. >>> count_duplicates({'R': 1, 'G': 2, 'B': 2, 'Y': 1, 'P': 3}) 2 """ duplicates = 0 values = list(dictionary.values()) for item in values: # if an item appears at least 2 times, it is a duplicate if values.count(item) >= 2: duplicates = duplicates + 1 # remove that item from the list num_occurrences = values.count(item) for i in range(num_occurrences): values.remove(item) return duplicates

6. This one is a fun challenge. Edsgar Dijkstra is known for his work on programming languages. He came up with a neat problem that he called the Dutch National Flag problem: given a list of strings, each of which is either 'red', 'green', or 'blue' (each is repeated several times in the list), rearrange the list so that the strings are in the order of the Dutch national flag—all the 'red' strings first, then all the 'green' strings, then all the 'blue' strings. Write a function called dutch_flag that takes a list and solves this problem.

6. def dutch_flag(color_list): """ (list of str) -> list of str Return color_list rearranged so that 'red' strings come first, 'green' second, and 'blue' third. >>> color_list = ['red', 'green', 'blue', 'red', 'red', 'blue', 'red', 'green'] >>> dutch_flag(['red', 'green', 'blue', 'red', 'red', 'blue', 'red', 'green']) >>> color_list ['red', 'red', 'red', 'red', 'green', 'green', 'blue', 'blue'] """ i = 0 # The start of the green section. start_green = 0 # The index of the first unexamined color. start_unknown = 0 # The index of the last unexamined color. end_unknown = len(color_list) - 1 print(color_list) print('start') while start_unknown <= end_unknown: # If it is red, swap it with the item to the right of the red section. if color_list[start_unknown] == 'red': color_list[start_green], color_list[start_unknown] \ = color_list[start_unknown], color_list[start_green] start_green += 1 start_unknown += 1 # If it is green, leave it where it is. elif color_list[start_unknown] == 'green': start_unknown += 1 # If it is blue, swap it with the item to the left of the blue section. else: color_list[start_unknown], color_list[end_unknown] \ = color_list[end_unknown], color_list[start_unknown] end_unknown -= 1

6. Modify the file reader in read_smallest_skip.py of Skipping the Header, on page 183, so that it uses a continue inside the loop instead of an if. Which form do you find easier to read?

6. import time_series def smallest_value_skip(reader): """ (file open for reading) -> NoneType Read and process reader, which must start with a time_series header. Return the smallest value after the header. Skip missing values, which are indicated with a hyphen. """ line = time_series.skip_header(reader).strip() # Now line contains the first data value; this is also the smallest value # found so far, because it is the only one we have seen. smallest = int(line) for line in reader: line = line.strip() if line == '-': continue value = int(line) smallest = min(smallest, value) return smallest if __name__ == '__main__': with open('hebron.txt', 'r') as input_file: print(smallest_value_skip(input_file))

6. In Section 9.7, Repetition Based on User Input, on page 161, you saw a loop that prompted users until they typed quit. This code won't work if users type Quit, or QUIT, or any other version that isn't exactly quit. Modify that loop so that it terminates if a user types that word with any capitalization.

6. text = "" while text.lower() != "quit": text = input("Please enter a chemical formula (or 'quit' to exit): ") if text == "quit": print("...exiting program") elif text == "H2O": print("Water") elif text == "NH3": print("Ammonia") elif text == "CH4": print("Methane") else: print("Unknown compound")

6. Using string method replace, write an expression that produces a string based on 'runner' with the n's replaced by b's.

6. 'runner'.replace('n', 'b')

6. Consider this code: >>> first = 'John' >>> last = 'Doe' >>> print(last + ', ' + first) What is printed by the code above?

6. Doe, John

6. In this exercise, you'll create a list and then answer questions about that list. a. Create a list of temperatures in degrees Celsius with the values 25.2, 16.8, 31.4, 23.9, 28, 22.5, and 19.6, and assign it to a variable called temps. b. Using one of the list methods, sort temps in ascending order. c. Using slicing, create two new lists, cool_temps and warm_temps, which contain the temperatures below and above 20 degrees Celsius, respectively. d. Using list arithmetic, recombine cool_temps and warm_temps into a new list called temps_in_celsius.

6. a. temps = [25.2, 16.8, 31.4, 23.9, 28, 22.5, 19.6] b. temps.sort() c. cool_temps = temps[0:2] warm_temps = temps[2:] d. temps_in_celsius = cool_temps + warm_temps

7. Modify the timing program to compare bubble sort with insertion and selection sort. Explain the results.

7. The results: n bubble select insert builtin ======================================== 10 0.0 0.0 0.0 0.0 1000 85.7 78.6 31.6 0.2 2000 332.2 317.0 128.2 0.4 3000 792.5 683.8 285.8 0.6 4000 1400.3 1246.1 517.6 0.9 5000 2111.7 1968.4 836.2 1.2 10000 8762.9 7625.9 3118.3 2.5 Bubble sort is the worst of all of them. This is probably because selection sort performs 1 swap to put an item in its place, but bubble sort may have many swaps on a single sweep.

7. A balanced color is one whose red, green, and blue values add up to 1.0. Write a function called is_balanced that takes a dictionary whose keys are 'R', 'G', and 'B' and whose values are between 0 and 1 as input and returns True if they represent a balanced color.

7. def is_balanced(color_to_factor): """ (dict of {str: float}) -> bool Return True if and only if color_to_factor represents a balanced color. >>> is_balanced({'R': 0.5, 'G': 0.4, 'B': 0.7}) False >>> is_balanced({'R': 0.3, 'G': 0.5, 'B': 0.2}) True """ values = list(color_to_factor.values()) total = sum(values) return total == 1.0

7. Modify the PDB file reader of Section 10.7, Multiline Records, on page 191, so that it ignores blank lines and comment lines in PDB files. A blank line is one that contains only space and tab characters (that is, one that looks empty when viewed). A comment is any line beginning with the keyword CMNT.

7. def read_molecule(reader): """ (file open for reading) -> list or NoneType Read a single molecule from reader and return it, or return None to signal end of file. The first item in the result is the name of the compound; each list contains an atom type and the X, Y, and Z coordinates of that atom. """ # If there isn't another line, we're at the end of the file. line = reader.readline() if not line: return None if not (line.startswith('CMNT') or line.isspace()): # Name of the molecule: "COMPND name" key, name = line.split() # Other lines are either "END" or "ATOM num atom_type x y z" molecule = [name] else: molecule = None reading = True while reading: line = reader.readline() if line.startswith('END'): reading = False elif not (line.startswith('CMNT') or line.isspace()): key, num, atom_type, x, y, z = line.split() if molecule == None: molecule = [] molecule.append([atom_type, x, y, z]) return molecule

7. Complete the examples in the docstring and then write the body of the following function: def same_first_last(L): """ (list) -> bool Precondition: len(L) >= 2 Return True if and only if first item of the list is the same as the last. >>> same_first_last([3, 4, 2, 8, 3]) True >>> same_first_last(['apple', 'banana', 'pear']) >>> same_first_last([4.0, 4.5]) """

7. def same_first_last(L): """ (list) -> bool Precondition: len(L) >= 2 Return True if and only if first item of the list is the same as the last. >>> same_first_last([3, 4, 2, 8, 3]) True >>> same_first_last(['apple', 'banana', 'pear']) False >>> same_first_last([4.0, 4.5]) False """ return L[0] == L[-1]

7. Following the function design recipe, define a function that has four parameters, all of them grades between 0 and 100 inclusive, and returns the average of the best 3 of those grades. Hint: Call the function that you defined in the previous exercise.

7. def top_three_avg(grade1, grade2, grade3, grade4): """ (number, number, number, number) -> number Return the average of the top three of grades grade1, grade2, grade3, and grade4. >>> top_three_avg(50, 60, 70, 80) 70 """ # Here is one solution that does not use average_grade from Q6. total = grade1 + grade2 + grade3 + grade4 top_three = total - min(grade1, grade2, grade3, grade4) return top_three / 3 # Here is a different solution that does use the function from Q6. return max(average_grade(grade1, grade2, grade3), average_grade(grade1, grade2, grade4), average_grade(grade1, grade3, grade4), average_grade(grade2, grade3, grade4))

7. Use input to prompt the user for a number, store the number entered as a float in a variable named num, and then print the contents of num.

7. num = float(input()) print(num)

7. Consider the following statement, which creates a list of populations of countries in eastern Asia (China, DPR Korea, Hong Kong, Mongolia, Republic of Korea, and Taiwan) in millions: country_populations = [1295, 23, 7, 3, 47, 21]. Write a for loop that adds up all the values and stores them in variable total. (Hint: Give total an initial value of zero, and, inside the loop body, add the population of the current country to total.)

7. total = 0 for population in country_populations: total += population

7. Variable s refers to ' yes '. When a string method is called with s as its argument, the string 'yes' is produced. Which string method was called?

7. strip

8. The analysis of bin_sort said, "Since N values have to be inserted, the overall running time is N log2 N." Point out a flaw in this reasoning, and explain whether it affects the overall conclusion

8. On the first iteration, binary search is performed on only 2 items; on each iteration, the size of the sublist being searched grows by one. So N log_2 N is an upper bound on the estimate of the overall running time, but not an egregious one.

8. Write a function called dict_intersect that takes two dictionaries as arguments and returns a dictionary that contains only the key/value pairs found in both of the original dictionaries.

8. def dict_interest(dict1, dict2): """ (dict, dict) -> dict Return a new dictionary that contains only the key/value pairs that occur in both dict1 and dict2. >>> dict_interest({'a': 1, 'b': 2, 'c': 3}, {'a': 1, 'd': 2, 'b': 2}) {'a': 1, 'b': 2} """ intersection = {} for (key, value) in dict1.items(): if key in dict2 and value == dict2[key]: intersection[key] = value return intersection

8. Complete the examples in the docstring and then write the body of the following function: def is_longer(L1, L2): """ (list, list) -> bool Return True if and only if the length of L1 is longer than the length of L2. >>> is_longer([1, 2, 3], [4, 5]) True >>> is_longer(['abcdef'], ['ab', 'cd', 'ef']) >>> is_longer(['a', 'b', 'c'], [1, 2, 3] """

8. def is_longer(L1, L2): """ (list, list) -> bool Return True if and only if the length of L1 is longer than the length of L2. >>> is_longer([1, 2, 3], [4, 5]) True >>> is_longer(['abcdef'], ['ab', 'cd', 'ef']) False >>> is_longer(['a', 'b', 'c'], [1, 2, 3]) False """ return len(L1) > len(L2)

8. Modify the PDB file reader to check that the serial numbers on atoms start at 1 and increase by 1. What should the modified function do if it finds a file that doesn't obey this rule?

8. def read_molecule(reader): """ (file open for reading) -> list or NoneType Read a single molecule from reader and return it, or return None to signal end of file. The first item in the result is the name of the compound; each list contains an atom type and the X, Y, and Z coordinates of that atom. """ # If there isn't another line, we're at the end of the file. line = reader.readline() if not line: return None # Name of the molecule: "COMPND name" key, name = line.split() # Other lines are either "END" or "ATOM num atom_type x y z" molecule = [name] reading = True serial_number = 1 while reading: line = reader.readline() if line.startswith('END'): reading = False else: key, num, atom_type, x, y, z = line.split() if int(num) != serial_number: print('Expected serial number {0}, but got {1}'.format( serial_number, num)) molecule.append([atom_type, x, y, z]) serial_number += 1 return molecule

8. Complete the examples in the docstring and then write the body of the following function: def repeat(s, n): """ (str, int) -> str Return s repeated n times; if n is negative, return the empty string. >>> repeat('yes', 4) 'yesyesyesyes' >>> repeat('no', 0) >>> repeat('no', -2) >>> repeat('yesnomaybe', 3) """

8. def repeat(s, n): """ (str, int) -> str Return s repeated n times; if n is negative, return the empty string. >>> repeat('yes', 4) 'yesyesyesyes' >>> repeat('no', 0) '' >>> repeat('no', -2) '' >>> repeat('yesnomaybe', 3) 'yesnomaybeyesnomaybeyesnomaybe' """ return s * n

8. Complete the examples in the docstring and then write the body of the following function: def weeks_elapsed(day1, day2): """ (int, int) -> int day1 and day2 are days in the same year. Return the number of full weeks that have elapsed between the two days. >>> weeks_elapsed(3, 20) 2 >>> weeks_elapsed(20, 3) 2 >>> weeks_elapsed(8, 5) >>> weeks_elapsed(40, 61) """

8. def weeks_elapsed(day1, day2): """ (int, int) -> int day1 and day2 are days in the same year. Return the number of full weeks that have elapsed between the two days. >>> weeks_elapsed(3, 20) 2 >>> weeks_elapsed(20, 3) 2 >>> weeks_elapsed(8, 5) 0 >>> weeks_elapsed(40, 61) 3 """ return int(abs(day1 - day2) / 7)

8. You are given two lists, rat_1 and rat_2, that contain the daily weights of two rats over a period of ten days. Assume the rats never have exactly the same weight. Write statements to do the following: a. If the weight of rat 1 is greater than that of rat 2 on day 1, print "Rat 1 weighed more than rat 2 on day 1."; otherwise, print "Rat 1 weighed less than rat 2 on day 1.". b. If rat 1 weighed more than rat 2 on day 1 and if rat 1 weighs more than rat 2 on the last day, print "Rat 1 remained heavier than Rat 2."; otherwise, print "Rat 2 became heavier than Rat 1." c. If your solution to the previous exercise used nested if statements, then do it without nesting, or vice versa.

8. a. if rat_1[0] > rat_2[0]: print("Rat 1 weighed more than rat 2 on day 1.") else: print("Rat 1 weighed less than rat 2 on day 1.") b. if rat_1[0] > rat_2[0] and rat_1[-1] > rat_2[-1]: print("Rat 1 remained heavier than Rat 2.") else print("Rat 2 became heavier than Rat 1.") c. if rat_1[0] > rat_2[0]: if rat_1[-1] > rat_2[-1]: print("Rat 1 remained heavier than Rat 2.") else: print("Rat 2 became heavier than Rat 1.") else print("Rat 2 became heavier than Rat 1.")

8. Variable fruit refers to 'pineapple'. For the following function calls, in what order are the subexpressions evaluated? a. fruit.find('p', fruit.count('p')) b. fruit.count(fruit.upper().swapcase()) c. fruit.replace(fruit.swapcase(), fruit.lower())

8. a. fruit.count('p') then fruit.find('p', 3) b. fruit.upper() then 'PINEAPPLE'.swapcase() then fruit.count('pineapple') c. fruit.swapcase() then fruit.lower() then fruit.replace('PINEAPPLE', 'pineapple')

9. There are at least two ways to come up with loop conditions. One of them is to answer the question, "When is the work done?" and then negate it. In function merge in Merging Two Sorted Lists, on page 261, the answer is, "When we run out of items in one of the two lists," which is described by this expression: i1 == len(L1) or i2 == len(L2). Negating this leads to our condition i1 != len(L1) and i2 != len(L2). Another way to come up with a loop condition is to ask, "What are the valid values of the loop index?" In function merge, the answer to this is 0 <= i1 < len(L1) and 0 <= i2 < len(L2); since i1 and i2 start at zero, we can drop the comparisons with zero, giving us i1 < len(L1) and i2 < len(L2). Is there another way to do it? Have you tried both approaches? Which do you prefer?

9. A third way to do it, as practiced by many novice programmers (including ourselves back when we started!) is to make a guess, and then keep fussing with the code until it works. We have learned by experience that this almost never saves time, and often can triple or quadruple the amount of time we spend. We personally prefer the first version, because there are only a small number of ways for the loop to be done, but many ways for it to continue.

9. Programmers sometimes use a dictionary of dictionaries as a simple database. For example, to keep track of information about famous scientists, you might have a dictionary where the keys are strings and the values are dictionaries, like this: { 'jgoodall' : {'surname' : 'Goodall', 'forename' : 'Jane', 'born' : 1934, 'died' : None, 'notes' : 'primate researcher', 'author' : ['In the Shadow of Man', 'The Chimpanzees of Gombe']}, 'rfranklin' : {'surname' : 'Franklin', 'forename' : 'Rosalind', 'born' : 1920, 'died' : 1957, 'notes' : 'contributed to discovery of DNA'}, 'rcarson' : {'surname' : 'Carson', 'forename' : 'Rachel', 'born' : 1907, 'died' : 1964, 'notes' : 'raised awareness of effects of DDT', 'author' : ['Silent Spring']} Write a function called db_headings that returns the set of keys used in any of the inner dictionaries. In this example, the function should return set('author', 'forename', 'surname', 'notes', 'born', 'died').

9. def db_headings(dict_of_dict): """ (dict of dict) -> set Return a set of the keys in the inner dictionaries in dict_of_dict. >>> db_headings({'A': {1: 'a', 2: 'b'}, 'B': {2: 'c', 3: 'd'}}) {1, 2, 3} """ inner_keys = set() for key in dict_of_dict: for inner_key in dict_of_dict[key]: inner_keys.add(inner_key) return inner_keys

9. Complete the examples in the docstring and then write the body of the following function: def total_length(s1, s2): """ (str, str) -> int Return the sum of the lengths of s1 and s2. >>> total_length('yes', 'no') 5 >>> total_length('yes', '') >>> total_length('YES!!!!', 'Noooooo') """

9. def total_length(s1, s2): """ (str, str) -> int Return the sum of the lengths of s1 and s2. >>> total_length('yes', 'no') 5 >>> total_length('yes', '') 3 >>> total_length('YES!!!!', 'Noooooo') 14 """ return len(s1) + len(s2)

1. Write a for loop to print all the values in the celegans_phenotypes list from Section 8.4, Slicing Lists, on page 137, one per line. celegans_phenotypes refers to ['Emb', 'Him', 'Unc', 'Lon', 'Dpy', 'Sma'].

for phenotype in celegans_phenotypes: print(phenotype)

2. Write a for loop to print all the values in the half_lives list from Section 8.3, Operations on Lists, on page 134, all on a single line. half_lives refers to [87.74, 24110.0, 6537.0, 14.4, 376000.0].

for value in half_lives: print(value, end=' ')

4. In this exercise, you'll create a nested list and then write code that performs operations on that list. a. Create a nested list where each element of the outer list contains the atomic number and atomic weight for an alkaline earth metal. The values are beryllium (4 and 9.012), magnesium (12 and 24.305), calcium (20 and 40.078), strontium (38 and 87.62), barium (56 and 137.327), and radium (88 and 226). Assign the list to variable alkaline_earth_metals. b. Write a for loop to print all the values in alkaline_earth_metals, with the atomic number and atomic weight for each alkaline earth metal on a different line. c. Write a for loop to create a new list called number_and_weight that contains the elements of alkaline_earth_metals in the same order but not nested.

more_whales.append(count + 1) 4. a. alkaline_earth_metals = [[4, 9.012], [12, 24.305], [20, 40.078], [38, 87.62], [56, 137.327], [88, 226]] b. for inner_list in alkaline_earth_metals: print(inner_list[0]) print(inner_list[1]) c. number_and_weight = [] for inner_list in alkaline_earth_metals: number_and_weight.append(inner_list[0]) number_and_weight.append(inner_list[1])


संबंधित स्टडी सेट्स

International Law Exam #2 Study Guide

View Set

ch. 8: emergency care, first aid, and disasters

View Set

Pysch Notes - incorrection portion- ch1-9

View Set

Science Fiction Midterm Study Guide

View Set