### CS30 - Spring 2015 - Class 6

#### Example code in this lecture

scores-lists.py
more-lists.py
higher_order_functions.py

#### Lecture notes

• admin
- class participation
- assignment 2
- assignment 3

• back to our grades program: look at scores-lists.py code
- there is a function called get_scores. That gets the scores and returns them as a list. How?
- starts with an empty list
- uses append to add them on to the end of the list
- returns the list when the loop finishes
- average function
- has a single parameter, but this parameter will represent a list
- inelegant_average
- calculates the sum and divides by the number of entries
- uses a for loop to iterate over the values
- often, we'll use something besides "i" as a variable name that makes our program more readable
- is there a better way to do this?
- look at fancy_average
- us the sum function over lists
- median function
- sorts the values
- notice again that sort does NOT return a value, but sorts the list that it is called on
- returns the middle entry

• What does the sum_list function do in more-lists.py code?
- takes as input a list
- what is the type of the list?
- has to be numbers... result starts out as a number so we can only add other numbers to it
- sums up all of the numbers in the list
- result starts out at 0
- it then iterates through all of the elements in the list and adds it on

• What does the list_to_string function do in more-lists.py code?
- takes as input a list
- what is the type of the list?
- a list of almost anything!
- anything that we can call str() on (which turns out to be lots of things)
- concates all the items in the list into a single string
- results starts out as the empty string
- it iterates through each item in the list and concatenates them on to the results
- this is similar to our example before of summing up all the numbers in a list

• From strings to lists
- Remember last time I said that there are a category of things called "sequences"
- They support a number of shared behaviors:
- indexing
- slicing
- iterating over using for loops
- asking the length of (using len)
- Strings are sequences

• Strings are immutable!
- Strings and lists share some functionalies
- However, be careful, they don't share all functionalities
- Strings are immutable. What does immutable mean?
- Are not changeable
- For example:
>>> some_list = ["a", "b", "c", "d"]
>>> some_list
['a', 'b', 'c', 'd']
>>> some_list[0] = "car"
>>> some_list
['car', 'b', 'c', 'd']

>>> fruit = "banana"
>>> fruit[0] = "a"
Traceback (most recent call last):
File "<string>", line 1, in <fragment>
TypeError: 'str' object does not support item assignment

• tuples (immutable lists)
- For a variety of reasons (we'll get into some eventually), we also have immutable lists, called tuples
- tuples can be created as literals using parenthesis (instead of square braces)
>>> my_tuple = (1, 2, 3, 4)
>>> my_tuple
(1, 2, 3, 4)
>>> another_tuple = ("a", "b", "c", "d")
>>> another_tuple
('a', 'b', 'c', 'd')

- notice that when they print out they also show using parenthesis
- tuples are sequences and support all the functionality that sequences have:
>>> my_tuple[0]
1
>>> my_tuple[3]
4
>>> for i in range(len(my_tuple)):
...    print my_tuple[i]
...
1
2
3
4
>>> my_tuple[1:3]
(2, 3)
- tuples are immutable!
>>> my_tuple[0] = 1
Traceback (most recent call last):
File "<string>", line 1, in <fragment>
TypeError: 'tuple' object does not support item assignment
>>> my_tuple.append(1)
Traceback (most recent call last):
File "<string>", line 1, in <fragment>
AttributeError: 'tuple' object has no attribute 'append'

• A few cool tricks with tuples
- unpacking a tuple
- if we know how many items are in a tuple we can "unpack" it into individual variables

>>> my_tuple = (1, 2, 3)
>>> my_tuple
(1, 2, 3)
>>> (x, y, z) = my_tuple
>>> x
1
>>> y
2
>>> z
3

- we can also use this feature to assign to multiple variables in one statement:

>>> (x, y, z) = (10, 11, 12)
>>> x
10
>>> y
11
>>> z
12
>>> x, y, z = 10, 11, 12
>>> x, y, z = "apple", "banana", "pineapple"
>>> x
'apple'
>>> y
'banana'
>>> z
'pineapple'

notice that we can actually leave off the parenthesis and it still does the right thing

- swapping value in two variables

>>> x = 10
>>> y = 20

- what will the following statement do?

>>> x, y = y, x

- evaluate the right hand side giving us the tuple (20, 10)
- then assign that to the variables x and y

>>> x
20
>>> y
10

swapping the values in the two variables!

• Alternate ways of iterating over lists
- Write a function called multiply_lists that takes two lists of numbers and creates a new list with the values pairwise multiplied, e.g.

>>> list1 = [1, 2, 1, 2]
>>> list2 = [1, 2, 3, 4]
>>> multiply_lists(list1, list2)
[1, 4, 3, 8]

- In words, what would we like to do?
- Go through the lists at the same time
- Multiply each element together
- Append onto a new list

- How do we go through the lists at the same time?
- Hint: Here's another way we can iterate through a list

for item in list:
print item

is equivalent to:

for i in range(len(list)):
print list[i]

- in the second example we're iterating of the indices from 0 up to the length of the list - 1 and then indexing into the lists

- Look at multiply_lists function in more-lists.py code
- What does the if statement check?
- make sure they're the same length
- the for loop then iterates over the indices and multiplies the corresponding ones

• higher order functions
- have you ever typed a function into the shell, but forgot the parentheses?
>>> multiply_lists
<function multiply_lists at 0x10cd15398>
>>> abs
<built-in function abs>

- Notice that it does NOT give an error
- Instead, it echoes the value, just like any other expression, in this case, the value is a function!

- what do the first four function in higher_order_functions.py code do?
- take two arguments and do standard mathematical calculations

- what does apply_function do in higher_order_functions.py code?
- takes three arguments
- the first is a function!
- applies the function passed as the first argument to the second and third argument and returns the result

- functions in python are just like other types of values, e.g. ints, floats, strings, etc
- we can assign them to variables
- for example:

>>> my_abs = abs
>>> my_abs(-10)
10
- we can pass them as parameters
- we can return them from functions
- we can even create them on the fly! (more on this later)

- We can call our apply_function function:
>>> apply_function(add, 2, 3)
5
>>> apply_function(subtract, 2, 3)
-1

- to pass a function as a parameter you just give the name of the function as the argument

- def
- what the keyword def actually does is
1) create a new function
2) assign that function to a variable with the name of the function

• map
- what does the apply_function_to_list function do in higher_order_functions.py code?
- takes a function and a list as parameters
- you can tell that the parameter "function" is a function because we apply it in the line with the append in it
- iterates through each value in the list
- applies the function
- appends the result of the function to a list that is then returned
- High-level: applies the function to each element in the list and returns a new list containing the result from each of those applications
- For example:
>>> apply_function_to_list(double, [1, 2, 3, 4])
[2, 4, 6, 8]
- There is actually a built-in function in python that does this called "map"

>>> map(double, [1, 2, 3, 4])
[2, 4, 6, 8]

• filter
- what does the filter_list function do in higher_order_functions.py code?
- also takes a function and a list as parameters

- are there any expectations on what the function should do/return?
- it's used in an if statement
- it should return a bool, i.e. True or False
- The filter function is like map in that it applies the function to every element in the list
- BUT, it only keeps those where the function returns True for that element

- For example,
>>> map(is_even, [1, 2, 3, 4])
[False, True, False, True]
>>> filter_list(is_even, [1, 2, 3, 4])
[2, 4]

- There is actually a built-in function called filter that does exactly what our filter_list function does:
>>> filter(is_even, [1, 2, 3, 4])
[2, 4]