More Looping Answers

Tuple Exercises

Hint

If you get stuck for a minute or more, try searching Google or using help.

If you’re stuck for more than a few minutes, some of these links might be helpful for some of the exercises below:

Hot Dog Packs

File: Edit the hotdog_counts function in the tuples.py file that is in the exercises directory.

Test: Run python test.py hotdog_counts in your exercises directory.

Exercise: We’re hosting a party and we need to know how many hot dog buns and hot dogs we need.

Buns and dogs are sold in packs of different sizes:

  • 8 buns are in 1 pack of buns

  • 10 hot dogs are in 1 pack of dogs

Create a function hotdog_counts which accepts the number of guests and returns a two-item tuple containing the number of bun packs and the number of dog packs we need (bun packs first, dog packs second).

>>> from tuples import hotdog_counts
>>> hotdog_counts(7)
(1, 1)
>>> hotdog_counts(10)
(2, 1)
>>> hotdog_counts(14)
(2, 2)
>>> hotdog_counts(20)
(3, 2)
>>> hotdog_counts(21)
(3, 3)

Hint

You’ll need to calculate how many packs are needed by dividing and rounding up. Use math.ceil() to round upward, or use integer division with a trick.

Answers

Using math.ceil:

import math

def hotdog_counts(guests):
    """Return tuple of bun packs and dog packs needed for given guests."""
    bun_packs = math.ceil(guests / 8)
    dog_packs = math.ceil(guests / 10)
    return (bun_packs, dog_packs)

Using integer division trick:

def hotdog_counts(guests):
    """Return tuple of bun packs and dog packs needed for given guests."""
    bun_packs = (guests + 7) // 8  # Add 7 to round up when dividing by 8
    dog_packs = (guests + 9) // 10  # Add 9 to round up when dividing by 10
    return (bun_packs, dog_packs)

Parse Time

File: Edit the parse_time function in the file functions.py that is in the exercises directory.

Test: Run python test.py parse_time in your exercises directory.

Exercise: Edit the function parse_time so that it takes an input time string in the format of “minutes:seconds”, uses tuple unpacking to extract the minutes and seconds, calculates and returns the total number of seconds. You can assume the string will contain at least one digit each for minutes and seconds.

>>> from functions import parse_time
>>> parse_time("4:03")
243
>>> parse_time("0:12")
12
>>> parse_time("1:10")
70

Answers

def parse_time(time_string):
    """Return total seconds from string of minutes:seconds."""
    minutes, seconds = time_string.split(':')
    return int(minutes) * 60 + int(seconds)

Format Time

File: Edit the format_time function in the file functions.py that is in the exercises directory.

Test: Run python test.py format_time in your exercises directory.

Exercise: Edit the function format_time so that it takes an integer value of seconds and calculates minutes and seconds, then returns a string of “minutes:seconds”. If the value of seconds is less than 10, a zero should be prefixed so the seconds are always 2 digits.

>>> from functions import format_time
>>> format_time(90061)
'1501:01'
>>> format_time(0)
'0:00'
>>> format_time(3600)
'60:00'
>>> format_time(301)
'5:01'
>>> format_time(3715)
'61:55'
>>> format_time(61)
'1:01'
>>> format_time(119)
'1:59'
>>> format_time(333)
'5:33'

Answers

def format_time(seconds):
    """Return a minutes:seconds string based on input seconds."""
    minutes, seconds = divmod(seconds, 60)
    return f"{minutes}:{seconds:02d}"

Swap Ends

File: Edit the swap_ends function in the tuples.py file that is in the exercises directory.

Test: Run python test.py swap_ends in your exercises directory.

Exercise: Edit the function swap_ends so that it swaps the first and last items in a given list, in-place.

>>> from tuples import swap_ends
>>> numbers = [1, 2, 3, 4, 5]
>>> swap_ends(numbers)
>>> numbers
[5, 2, 3, 4, 1]

Answers

def swap_ends(sequence):
    """Swap the first and last items in the given list."""
    sequence[0], sequence[-1] = sequence[-1], sequence[0]

Earliest

File: Edit the get_earliest function in the tuples.py file that is in the exercises directory.

Test: Run python test.py get_earliest in your exercises directory.

Exercise: Make function get_earliest that accepts two dates in MM/DD/YYYY format and returns the date that is earliest.

>>> from tuples import get_earliest
>>> get_earliest("01/27/1832", "01/27/1756")
'01/27/1756'
>>> get_earliest("02/29/1972", "12/21/1946")
'12/21/1946'
>>> get_earliest("03/21/1946", "02/24/1946")
'02/24/1946'
>>> get_earliest("06/24/1958", "06/21/1958")
'06/21/1958'

Note

Want to test this out manually (instead of using python test.py)?

You could could create a file called get_earliest_test.py with your own test code:

from tuples import get_earliest

print('Calling get_earliest("01/27/1832", "01/27/1756")')
print("Expected: 01/27/1756")
print("  Actual:", get_earliest("01/27/1832", "01/27/1756"))

print()

print('Calling get_earliest("02/29/1972", "12/21/1946")')
print("Expected: 12/21/1946")
print("  Actual:", get_earliest("02/29/1972", "12/21/1946"))

print()

print('Calling get_earliest("03/21/1946", "02/24/1946")')
print("Expected: 02/24/1946")
print("  Actual:", get_earliest("03/21/1946", "02/24/1946"))

print()

print('Calling get_earliest("06/24/1958", "06/21/1958")')
print("Expected: 06/21/1958")
print("  Actual:", get_earliest("06/24/1958", "06/21/1958"))

Then you can run that file to test your code:

$ python get_earliest_test.py

Answers

With tuple unpacking and if statement:

def get_earliest(date1, date2):
    """Return earliest of two MM/DD/YYYY-formatted date strings."""
    (m1, d1, y1) = date1.split('/')
    (m2, d2, y2) = date2.split('/')
    if (y1, m1, d1) < (y2, m2, d2):
        return date1
    else:
        return date2

With inline if:

def get_earliest(date1, date2):
    """Return earliest of two MM/DD/YYYY-formatted date strings."""
    (m1, d1, y1) = date1.split('/')
    (m2, d2, y2) = date2.split('/')
    return date1 if (y1, m1, d1) < (y2, m2, d2) else date2

Name Key

File: Edit the name_key function in the tuples.py file that is in the exercises directory.

Test: Run python test.py name_key in your exercises directory.

Exercise: Write a function name_key that accepts a full name string and returns a last-first name tuple:

To test locally:

>>> from tuples import name_key
>>> suzanne = "Suzanne Smith"
>>> michael = "Michael Gambino"
>>> name_key(michael)
('Gambino', 'Michael')
>>> name_key(suzanne)
('Smith', 'Suzanne')

Answers

def name_key(name):
    """Return last-first name tuple from first-last name string."""
    first, last = name.split()
    return last, first

Sort Names

File: Edit the sort_names function in the tuples.py file that is in the exercises directory.

Test: Run python test.py sort_names in your exercises directory.

Exercise: Write a function sort_names that accepts a list of full name strings and returns a sorted list (using sorted with key).

The built-in sorted function accepts a key argument that determines how values should be sorted in a given iterable. You can use the name_key function you created above as the key argument.

Let’s use this function to sort a list of names. Names should be sorted by last name followed by first name (when the last names are equal).

>>> from tuples import sort_names
>>> names = ["Jill Moore", "Ben Speigel", "Tanya Jackson", "Evelyn Moore"]
>>> sort_names(names)
['Tanya Jackson', 'Evelyn Moore', 'Jill Moore', 'Ben Speigel']

Answers

def name_key(name):
    """Return last-first name tuple from first-last name string."""
    first, last = name.split()
    return last, first

def sort_names(names):
    """Return given first-last name tuples sorted by last name."""
    return sorted(names, key=name_key)

Counting Exercises

Line Numbers

This is the line_numbers.py exercise in the modules directory that we saw earlier in the Introduction to Files section. Create the file line_numbers.py in the modules sub-directory of the exercises directory. To test it, run python test.py line_numbers.py from your exercises directory.

Write a program that accepts a file as its only argument and prints out the lines in the files with a line number displayed in front of them. See if you can improve the code with what we have learned in this section.

Example:

If my_file.txt contains:

This file
is two lines long.
No wait, it's three lines long!

Running:

$ python line_numbers.py my_file.txt

Should print out:

1 This file
2 is two lines long.
3 No wait, it's three lines long!

Answers

import sys

filename = sys.argv[1]

with open(filename) as my_file:
    for lineno, line in enumerate(my_file, start=1):
        print(lineno, line, end='')

Guess in 3

Create a program guess.py in the modules sub-directory of the exercises directory. To test it, run python test.py guess.py from your exercises directory.

The program below generates a random number from 1 to 8 and gives the user 3 guesses to guess the number correctly. After each guess the program says either “Correct”, “Too high” or “Too low”.

Once a correct guess is made, the program ends. If the final guess is incorrect, the user is shown a message noting the correct number.

Your task: Refactor this code to use a for loop for readability’s sake.

import random

number = random.randint(1, 8)

print("I have selected a number between 1 and 8.")
print("You have 3 attempts to guess it correctly.")

guess = int(input("1) Enter your guess: "))
if guess < number:
    print("Too low")
    guess = int(input("2) Enter your guess: "))
    if guess < number:
        print("Too low")
        guess = int(input("3) Enter your guess: "))
        if guess < number:
            print("Too low")
            print(f"Incorrect. The correct number was {number}.")
        elif guess > number:
            print("Too high")
            print(f"Incorrect. The correct number was {number}.")
        else:
            print("Correct! You've guessed the number!")
    elif guess > number:
        print("Too high")
        guess = int(input("3) Enter your guess: "))
        if guess < number:
            print("Too low")
            print(f"Incorrect. The correct number was {number}.")
        elif guess > number:
            print("Too high")
            print(f"Incorrect. The correct number was {number}.")
        else:
            print("Correct! You've guessed the number!")
    else:
        print("Correct! You've guessed the number!")
elif guess > number:
    print("Too high")
    guess = int(input("2) Enter your guess: "))
    if guess < number:
        print("Too low")
        guess = int(input("3) Enter your guess: "))
        if guess < number:
            print("Too low")
            print(f"Incorrect. The correct number was {number}.")
        elif guess > number:
            print("Too high")
            print(f"Incorrect. The correct number was {number}.")
        else:
            print("Correct! You've guessed the number!")
    elif guess > number:
        print("Too high")
        guess = int(input("3) Enter your guess: "))
        if guess < number:
            print("Too low")
            print(f"Incorrect. The correct number was {number}.")
        elif guess > number:
            print("Too high")
            print(f"Incorrect. The correct number was {number}.")
        else:
            print("Correct! You've guessed the number!")
    else:
        print("Correct! You've guessed the number!")
else:
    print("Correct! You've guessed the number!")

Hint

Use a for loop with range(3) to iterate through the attempts. You can use break to exit the loop early when the correct guess is made, and for-else to handle the case where all guesses are exhausted.

Answers

Using a for loop with break:

import random

number = random.randint(1, 8)

print("I have selected a number between 1 and 8.")
print("You have 3 attempts to guess it correctly.")

for attempt in range(1, 4):
    guess = int(input(f"{attempt}) Enter your guess: "))
    if guess == number:
        print("Correct! You've guessed the number!")
        break
    elif guess < number:
        print("Too low")
    else:
        print("Too high")
else:
    print(f"Incorrect. The correct number was {number}.")

Alternative with for-else construct:

import random

number = random.randint(1, 8)

print("I have selected a number between 1 and 8.")
print("You have 3 attempts to guess it correctly.")

for attempt in range(1, 4):
    guess = int(input(f"{attempt}) Enter your guess: "))
    if guess == number:
        print("Correct! You've guessed the number!")
        break
    elif guess < number:
        print("Too low")
    else:
        print("Too high")
else:
    # This executes only if the loop wasn't broken
    print(f"Incorrect. The correct number was {number}.")

Factors

Edit the get_factors function in the ranges.py file so that it returns the factors of a given number. To test it, run python test.py get_factors in your exercises directory.

To test locally:

>>> from ranges import get_factors
>>> get_factors(2)
[1, 2]
>>> get_factors(6)
[1, 2, 3, 6]
>>> get_factors(100)
[1, 2, 4, 5, 10, 20, 25, 50, 100]

Note

Want to test this out manually (instead of using python test.py)?

You could could create a file called get_factors_test.py with your own test code:

from ranges import get_factors

print("Calling get_factors(2)")
print("Expected: [1, 2]")
print("  Actual:", get_factors(2))

print()

print("Calling get_factors(6)")
print("Expected: [1, 2, 3, 6]")
print("  Actual:", get_factors(6))

print()

print("Calling get_factors(100)")
print("Expected: [1, 2, 4, 5, 10, 20, 25, 50, 100]")
print("  Actual:", get_factors(100))

Then you can run that file to test your code:

$ python get_factors_test.py

Answers

def get_factors(number):
    """Return a list of all factors of the given number."""
    factors = []
    for x in range(1, number + 1):
        if number % x == 0:
            factors.append(x)
    return factors

Range Check

Edit the is_range function in the ranges.py file so that it returns True if the given list could be represented with a range of numbers (ignoring step), and False otherwise. To test it, run python test.py is_range in your exercises directory.

To test locally:

>>> from ranges import is_range
>>> is_range([5, 6, 7, 8])
True
>>> is_range([5, 6, 8])
False
>>> is_range([0, 2, 1, 3])
False
>>> is_range([0, 1, 2, 3])
True

Answers

def is_range(numbers):
    """Return True if given list could be represented by range with step 1."""
    first, last = numbers[0], numbers[-1]
    return list(range(first, last+1)) == numbers

Annual Return

This is the annual_return function in the ranges.py file. This function is meant to model financial investments (whether in a bank, stock, or some other asset that increases at a particular average rate each year).

The annual_return function should accept these keyword arguments:

  • start is the starting amount of money

  • annual_yield is the percentage that the money will increase each year on average

  • years is the number of years for which the money will be yielding a return (whether invested or in the interest-earning account)

  • annual_contribution is the amount of money that should be added at the end of every year.

Assuming a start value of $5,000, an annual yield of 7%, an annual contribution of $5,000, and 30 years of investment, the annual_return function should return an list like this:

>>> returns = annual_return(
...     start=5000,
...     annual_yield=0.07,
...     years=30,
...     annual_contribution=5000,
... )
>>> for amount in returns:
...     print(f"${amount:,.2f}")
...
$10,350.00
$16,074.50
$22,199.72
$28,753.70
$35,766.45
$43,270.11
$51,299.01
$59,889.94
$69,082.24
$78,918.00
$89,442.26
$100,703.21
$112,752.44
$125,645.11
$139,440.27
$154,201.09
$169,995.16
$186,894.82
$204,977.46
$224,325.88
$245,028.70
$267,180.70
$290,883.35
$316,245.19
$343,382.35
$372,419.12
$403,488.45
$436,732.65
$472,303.93
$510,365.21

Note that the annual contribution is added at the end of the year, but the annual yield is computed based on the starting amount at the beginning of each year (this is compounding interest which is the way stocks and bank accounts frequently work).

Answers

def annual_return(start=0, annual_yield=0, years=0, annual_contribution=0):
    """Return list that models annual return for a financial asset."""
    returns = []
    amount = start
    for year in range(years):
        amount += amount*annual_yield+annual_contribution
        returns.append(amount)
    return returns

Primality

Edit the is_prime function in the ranges.py file so that it returns True if a number is prime and False otherwise. To test it, run python test.py is_prime in your exercises directory.

To test locally:

>>> from ranges import is_prime
>>> is_prime(21)
False
>>> is_prime(23)
True

Answers

def is_prime(candidate):
    """Return True if candidate number is prime."""
    if candidate < 2:
        return False
    for n in range(2, candidate):
        if candidate % n == 0:
            return False
    return True

More performant:

from math import sqrt

def is_prime(candidate):
    """Return True if candidate number is prime."""
    if candidate < 2:
        return False
    for n in range(2, int(sqrt(candidate))+1):
        if candidate % n == 0:
            return False
    return True

Power List By Index

Edit the power_list function in the ranges.py file so that it accepts a list and returns a new list that contains each number raised to the i-th power where i is the index of that number in the given list. To test it, run python test.py power_list in your exercises directory.

To test locally:

>>> from ranges import power_list
>>> power_list([3, 2, 5])
[1, 2, 25]
>>> numbers = [78, 700, 82, 16, 2, 3, 9.5]
>>> power_list(numbers)
[1, 700, 6724, 4096, 16, 243, 735091.890625]

Answers

With enumerate (most idiomatic):

def power_list(numbers):
    """Return a list that contains each number raised to the i-th power."""
    powers = []
    for i, number in enumerate(numbers):
        powers.append(number ** i)
    return powers

With range:

def power_list(nums):
    """Return a list that contains each number raised to the i-th power."""
    new_list = []
    for i in range(len(nums)):
        new_list.append(nums[i] ** i)
    return new_list

Reverse Difference

This is the reverse_difference exercise in ranges.py. Edit the ranges.py file in the exercises directory to implement this exercise. To test it, run python test.py reverse_difference in your exercises directory.

Make a function reverse_difference that accepts a list of numbers and returns a new copy of the list with the reverse of the list subtracted.

Hint: Use enumerate. We will see a better way to do this later on.

Example usage:

>>> from ranges import reverse_difference
>>> reverse_difference([9, 8, 7, 6])
[3, 1, -1, -3]
>>> reverse_difference([1, 2, 3, 4, 5])
[-4, -2, 0, 2, 4]
>>> reverse_difference([3, 2, 1, 0])
[3, 1, -1, -3]
>>> reverse_difference([0, 0])
[0, 0]

Answers

def reverse_difference(numbers):
    """Return list of reversed numbers subtracted from itself."""
    reversed_nums = list(reversed(numbers))
    differences = []
    for i, n in enumerate(numbers):
        differences.append(n - reversed_nums[i])
    return differences

with_previous

Edit the function with_previous in ranges.py so that it accepts a sequence (list, string, etc.) and returns a new list that includes a tuple of each item and the previous item (the item just before it). The first “previous item” should be None. To test it, run python test.py with_previous in your exercises directory.

Hint: Use enumerate. We will see a better way to do this later on.

It should work like this:

>>> from ranges import with_previous
>>> numbers = [1, 2, 3, 4]
>>> with_previous(numbers)
[(1, None), (2, 1), (3, 2), (4, 3)]

Answers

def with_previous(sequence):
    """Provide each list item with item before it."""
    new_sequence = []
    for i, item in enumerate(sequence):
        if i == 0:
            new_sequence.append((item, None))
        else:
            new_sequence.append((item, sequence[i-1]))
    return new_sequence

Or, using Python’s version of the “ternary” operator:

def with_previous(sequence):
    """Provide each list item with item before it."""
    new_sequence = []
    for i, item in enumerate(sequence):
        previous = sequence[i - 1] if i else None
        new_sequence.append((item, previous))
    return new_sequence

Identity Matrix

File: Edit the identity function in the ranges.py file so that it takes as input a number size for the size of the matrix and returns an identity matrix of size x size elements. To test it, run python test.py identity in your exercises directory.

An identity matrix is a square matrix with ones on the main diagonal and zeros elsewhere. A 3 by 3 identity matrix looks like:

[[1, 0, 0], [0, 1, 0], [0, 0, 1]]

To test locally:

>>> from ranges import identity
>>> identity(3)
[[1, 0, 0], [0, 1, 0], [0, 0, 1]]
>>> identity(4)
[[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]
>>> identity(2)
[[1, 0], [0, 1]]

Answers

With an if statement:

def identity(size):
    """Return an identity matrix of size x size"""
    matrix = []
    for col in range(size):
        new_row = []
        for row in range(size):
            if row == col:
                new_row.append(1)
            else:
                new_row.append(0)
        matrix.append(new_row)
    return matrix

Or, we could take advantage of the internal values of True and False. This is considered by many to be a legal and reasonable thing to do in Python.

def identity(size):
    """Return an identity matrix of size x size"""
    matrix = []
    for col in range(size):
        new_row = []
        for row in range(size):
            new_row.append(int(row == col))
        matrix.append(new_row)
    return matrix

Matrix Addition

This is the matrix_add exercise in ranges.py. Edit the ranges.py file in the exercises directory to implement this exercise. To test it, run python test.py matrix_add in your exercises directory.

Edit the function matrix_add to accept two matrices (lists of lists of numbers) and return one matrix that includes each corresponding number in the two lists added together.

Hint: Use enumerate. We will see a better way to do this later on.

You should assume the lists of lists provided will always be the same size/shape.

>>> from ranges import matrix_add
>>> m1 = [[1, 2], [3, 4]]
>>> m2 = [[5, 6], [7, 8]]
>>> matrix_add(m1, m2)
[[6, 8], [10, 12]]
>>> m1 = [[1, 2, 3], [0, 4, 2]]
>>> m2 = [[4, 2, 1], [5, 7, 0]]
>>> matrix_add(m1, m2)
[[5, 4, 4], [5, 11, 2]]

Answers

def matrix_add(matrix1, matrix2):
    """Add corresponding numbers in given 2-D matrices."""
    combined = []
    for i, row1 in enumerate(matrix1):
        row = []
        for j, number in enumerate(row1):
            row.append(number + matrix2[i][j])
        combined.append(row)
    return combined

Pythagorean Triples

Edit the triples function in the ranges.py file so that it takes a number and returns a list of tuples of 3 integers where each tuple is a Pythagorean triple, and the integers are all less than the input number. To test it, run python test.py triples in your exercises directory.

A Pythagorean triple is a group of 3 integers a, b, and c, such that they satisfy the formula a**2 + b**2 = c**2

To test locally:

>>> from ranges import triples
>>> triples(15)
[(3, 4, 5), (5, 12, 13), (6, 8, 10)]
>>> triples(30)
[(3, 4, 5), (5, 12, 13), (6, 8, 10), (7, 24, 25), (8, 15, 17), (9, 12, 15), (10, 24, 26), (12, 16, 20), (15, 20, 25), (20, 21, 29)]

Answers

def triples(num):
    """Return list of Pythagorean triples less than input num"""
    triples_list = []
    for a in range(1, num):
        for b in range(a+1, num):
            for c in range(b+1, num):
                if a**2 + b**2 == c**2:
                    triples_list.append((a, b, c))
    return triples_list

Zip Exercises

Hint

If you get stuck for a minute or more, try searching Google or using help.

If you’re stuck for more than a few minutes, some of these links might be helpful for some of the exercises below:

Reverse Difference

This is the reverse_difference exercise we saw earlier in ranges.py. Edit the ranges.py file in the exercises directory to implement this exercise. To test it, run python test.py reverse_difference in your exercises directory.

The function reverse_difference accepts a list of numbers and returns a new copy of the list with the reverse of the list subtracted.

Re-write the code to use the zip function.

Example usage:

>>> from ranges import reverse_difference
>>> reverse_difference([9, 8, 7, 6])
[3, 1, -1, -3]
>>> reverse_difference([1, 2, 3, 4, 5])
[-4, -2, 0, 2, 4]
>>> reverse_difference([3, 2, 1, 0])
[3, 1, -1, -3]
>>> reverse_difference([0, 0])
[0, 0]

Note

Want to test this out manually (instead of using python test.py)?

You could could create a file called reverse_difference_test.py with your own test code:

from ranges import reverse_difference

print("Calling reverse_difference([9, 8, 7, 6])")
print("Expected: [3, 1, -1, -3]")
print("  Actual:", reverse_difference([9, 8, 7, 6]))

print()

print("Calling reverse_difference([1, 2, 3, 4, 5])")
print("Expected: [-4, -2, 0, 2, 4]")
print("  Actual:", reverse_difference([1, 2, 3, 4, 5]))

print()

print("Calling reverse_difference([3, 2, 1, 0])")
print("Expected: [3, 1, -1, -3]")
print("  Actual:", reverse_difference([3, 2, 1, 0]))

Then you can run that file to test your code:

$ python reverse_difference_test.py

Answers

def reverse_difference(numbers):
    """Return list of reversed numbers subtracted from numbers."""
    differences = []
    for n, m in zip(numbers, reversed(numbers)):
        differences.append(n - m)
    return differences

Matrix Addition

This is the matrix_add exercise we saw earlier in ranges.py. Edit the ranges.py file in the exercises directory to implement this exercise. To test it, run python test.py matrix_add in your exercises directory.

The function matrix_add accepts two matrices (lists of lists of numbers) and returns one matrix that includes each corresponding number in the two lists added together.

You should assume the lists of lists provided will always be the same size/shape.

Re-write the function to use the zip function.

>>> from ranges import matrix_add
>>> m1 = [[1, 2], [3, 4]]
>>> m2 = [[5, 6], [7, 8]]
>>> matrix_add(m1, m2)
[[6, 8], [10, 12]]
>>> m1 = [[1, 2, 3], [0, 4, 2]]
>>> m2 = [[4, 2, 1], [5, 7, 0]]
>>> matrix_add(m1, m2)
[[5, 4, 4], [5, 11, 2]]

Answers

def matrix_add(matrix1, matrix2):
    """Add corresponding numbers in given 2-D matrices."""
    combined = []
    for row1, row2 in zip(matrix1, matrix2):
        row = []
        for n, m in zip(row1, row2):
            row.append(n + m)
        combined.append(row)
    return combined

Parse two-line CSV data

This is the parse_row exercise in ranges.py. Edit the ranges.py file in the exercises directory to implement this exercise. To test it, run python test.py parse_row in your exercises directory.

Make a function parse_row that accepts a string consisting of two lines of comma-separated data and parses it, returning a dictionary where the keys are elements from the first row and the values are from the second row.

Example usage:

>>> from ranges import parse_row
>>> color_data = "purple,indigo,red,blue,green\n0.15,0.25,0.3,0.05,0.25"
>>> parse_row(color_data)
{'purple': '0.15', 'indigo': '0.25', 'red': '0.3', 'blue': '0.05', 'green': '0.25'}

Answers

Without unpacking:

def parse_row(input_data):
    """Return dictionary of keys from first CSV row and values from second."""
    rows = input_data.split("\n")
    row1 = rows[0].split(",")
    row2 = rows[1].split(",")
    new_dict = dict(zip(row1, row2))
    return new_dict

With unpacking (more idiomatic):

def parse_row(input_data):
    """Return dictionary of keys from first CSV row and values from second."""
    color_row, ratio_row = input_data.split("\n")
    colors = color_row.split(",")
    ratios = ratio_row.split(",")
    return dict(zip(colors, ratios))

with_previous

This is the with_previous exercise we’ve seen before in in ranges.py. It accepts a list and returns a new list that includes a tuple of each item and the previous item (the item just before it). The first “previous item” should be None. To test it, run python test.py with_previous in your exercises directory.

Re-write the code to use the zip function.

It should work like this:

>>> from ranges import with_previous
>>> numbers = [1, 2, 3, 4]
>>> with_previous(numbers)
[(1, None), (2, 1), (3, 2), (4, 3)]

Answers

def with_previous(sequence):
    """Provide each list item with item before it."""
    return list(zip(sequence, [None] + list(sequence)))

With *, which we haven’t learned about yet:

def with_previous(sequence):
    """Provide each list item with item before it."""
    return list(zip(sequence, [None, *sequence]))

Interleave

This is the interleave in ranges.py. The function accepts two iterables and returns a list with the items in each iterable “interleaved” (item 0 from iterable 1, then item 0 from iterable 2, then item 1 from iterable 1, and so on). Assume the two lists have the same length. To test it, run python test.py interleave in your exercises directory.

Re-write the code to use the zip function.

Example:

>>> from ranges import interleave
>>> interleave([1, 2, 3, 4], [5, 6, 7, 8])
[1, 5, 2, 6, 3, 7, 4, 8]
>>> interleave([1, 4, 7], [2, 5, 8])
[1, 2, 4, 5, 7, 8]

Answers

def interleave(iterable1, iterable2):
    """Return list of one item at a time from each given iterable."""
    interleaved = []
    for group in zip(iterable1, iterable2):
        for item in group:
            interleaved.append(item)
    return interleaved