Section 7. Sorting, Tuples, OOP, & Memory


Written by Juliette Woodrow

This week in section you are going to get practice with tuples, sorting, object oriented programming, and memory.

Tuples and Sorting

Below are some problems to practice workign with tuples and sorting.

  • Given a list of numbers, sort the numbers based on their absolute value. As an example, if you are trying to sort the following list, [3, 2, -1, 7, -7, 5, 14] your function would return [-1, 2, 3, 5, 7, -7, 14]. Reminder that you can find the absolute value of a number by calling the built in abs function as follows:
    >>> x = -7
    >>> abs(x)
    7
    
def sort_by_abs(num):
    return abs(num)

sorted(nums, key=sort_by_abs)

  • Given a list of numbers, sort the numbers based on the absolute value of their difference with pi. You can use 3.14 as an approximation of pi. As an example, if we use the same list as above, [3, 2, -1, 7, -7, 5, 14], your function would return [3, 2, 5, 7, -1, -7, 14]
PI = 3.14

def sort_by_abs_pi(num):
    return abs(PI - num)

sorted(nums, key=sort_by_abs_pi)

  • Given a list of strings, sort the list case insensitively. As an example, if you have the following list of strings, ['Mehran', 'juliette', 'KaTiE', 'CS106A', 'pYtHoN'] your function would return ['CS106A', 'juliette', 'KaTiE', 'Mehran', 'pYtHoN'].
def sort_without_case(s):
    return s.lower()

sorted(strs, key=sort_without_case)

  • Given a list of tuples representing addresses in the form (street_num, city, state, zipcode), sort the list of addresses based on the numeric value of the zipcode.
def sort_by_zipcode(tup):
    return tup[3]

sorted(addresses, key=sort_by_zipcode)

  • Given a list of tuples representing address in the same form as above, sort the list of addresses based on the absolute value of the difference of the zipcode and Stanford's Zipcode (which is 94305).
STANFORD_ZIPCODE = 94305

def sort_by_zipcode_stanford(tup):
    curr_zipcode = tup[3]
    return abs(STANFORD_ZIPCODE - curr_zipcode)

sorted(addresses, key=sort_by_zipcode_stanford)

  • Given a file with information on a single student, write a function that reads in a file and returns a tuple in the form (name, number_id, email, expected_grad_year, num_units). The file will be in the format as follows:
Juliette Woodrow
75000000
jwoodrow@stanford.edu
2022
243

If you read in the above file, your function should return ('Juliette Woodrow', 75000000, 'jwoodrow@stanford.edu', 2022, 243). Notice that the numerical values are stored in the tuple as integers.

def extract_student_info(filename):
    with open(filename) as f:
        student_info_lst = f.readlines()
        name = student_info_lst[0]
        num_id = int(student_info_lst[1])
        email = student_info_lst[2]
        expected_grad_year = int(student_info_lst[3])
        num_units = int(student_info_lst[4])
        return (name, num_id, email, expected_grad_year, num_units)

  • Given a list of tuples representing students in the form (name, number_id, email, expected_grad_year, num_units), write a function that sorts these tuples by their expected_grad_year in descending order.
def sort_by_grad_year(tup):
    return tup[3]

sorted(student_info_lst, key=sort_by_grad_year, reverse=True)

Object Oriented Programming

In this problem you are going to the blueprint for a Circle object in the circle.py file for use in the following program. The design of the circle class is up to you, but running the program below should give the output below.

circle_test.py

# import the Circle class from circle.py
from circle import Circle 

def main():
    # construct circle with radius 5
    circle = Circle (5) 
    
    # print the area of the circle
    print("The area of the circle is " + str(circle.get_area()))

    # print the circumference of the circle
    print("The circumference of the circle is " + str(circle.get_circumference()))
  
if __name__ == "__main__":
    main()

After running the above program, the output should be:

The area of the circle is 78.53981633974483
The circumference of the circle is 31.41592653589793

As a reminder, a circle with radius r has area πr2 and circumference 2πr. The value of π is stored in the constant math.pi, which you can access by importing the math module.

You are in charge of the blueprint for the circle class. As you think of how to design the circle class, consider what information should we store in the cirlce class? What methods need to exist?

# File: Circle.py

import math

class Circle:

    def __init__(self, radius):
        """
        Creates a Circle object and initializes the radius.
        """
        self.radius = radius   # instance variable to keep track of the radius

    def get_area(self):
        """
        Returns the area of this circle.
        """
        area = math.pi * (self.radius**2)
        return area

    def get_circumference(self):
        """
        Returns the circumference of this circle
        """
        circumference = math.pi * self.radius * 2
        return circumference

Memory

First-time programmers bump into a need for a deeper understanding of what is actually going on under the hood when observing that in some for loops, and in some helper functions, changes to variables sometimes persist and sometimes do not! Lets first look at a few programs to build up this mystery:

  • What will this print?
      def main():
      x = [1, 2, 3]
      y = x
      # does this change impact x?
      y.append(4)
      print(x)
    

Output: [1, 2, 3, 4] Notice how the change to y does impact the value of x


  • Now lets swap the third line for a different way of changing the variable y:
      def main():
      x = [1, 2, 3]
      y = x
      # does this change impact x?
      y = []
      print(x)
    

Output: [1, 2, 3] Notice how the change to y does not impact the value of x. Why is this different than example 1?


That single line change led to a very different result. How come one way of changing y affected x, but the other way did not? When students don't understand the difference between these two types of changes it makes it very hard to predict what for loops or functions with parameters will do.

Here are more examples of the same phenomena in other contexts. Our goal is to get you to the point where you can predict the output for each of these examples. When you are ready, check out this handout to start mastering the different ways of changing variables.

For each of these, predict the output.

For Each Loop

def main():
    my_list = [1, 2, 3]
    for value in original_list:
        # will this change impact my_list?
        value += 5
    print(my_list)

Output: [1, 2, 3] Here the change to value in the for loop body does not affect my_list


For Index Loop

def main():
    my_list = [1, 2, 3]
    for i in range(len(my_list)):
        # will this change impact my_list?
        my_list[i] += 5
    print(my_list)

Output: [6, 7, 8] Here the change to value in the for loop body does affect my_list


For Loop Mixed

def main():
    my_list = [1, 2, 3]
    for i in range(len(my_list)):
        # will this change impact my_list?
        value = my_list[i]
        value += 5
    print(my_list)

Output: [1, 2, 3] Here the change to value in the for loop body does not affect my_list


For Loop Over Pixels

def main():
    my_image = SimpleImage("dog.png")
    for pixel in my_image:
        # will this change impact my_image?
        pixel.red = 0
    my_image.show()

Yes! Each pixel in the image has its red channel set to zero. The image is changed.


Parameters Number

def main():
    x = 0
    add_five(x)
    print(x)

def add_five(x):
    # will this change impact the x in main?
    x += 5

Output: 0 Integers are immutable, so the change to x in add_five does not change the value of x in the main function.


Parameters List Append

def main():
    x = [1, 2, 3]
    add_five(x)
    print(x)

def add_five(some_list):
    # will this change impact the x in main?
    some_list.append(5)

Output: [1, 2, 3, 5] Yes, this will impact x in main.


Parameters List Assign

def main():
    x = [1, 2, 3]
    add_five(x)
    print(x)

def add_five(x):
    # will this change impact the x in main?
    x = [1, 2, 3, 5]

Output: [1, 2, 3] No, this will not impact the x in main becaue it is reassigning the variable x rather than modifying its contents.