Lecture 10 — Lists Part 2 ========================== Overview -------- - List copying versus list aliasing - Aliasing: creating new name for lists - Assignment - Function that change the lists that are input - For loops to go through lists - Copying: creating new lists - Concatentation, replication and slicing - Strings and lists List Aliasing ------------- - The assignment operator does NOT create a new list. Rather it creates a new name for an existing list: :: >>> L1 = [ 'cat', 'dog', 'ant', 'tiger', 'parrot' ] >>> L2 = L1 >>> L1 ['cat', 'dog', 'ant', 'tiger', 'parrot'] >>> L2 ['cat', 'dog', 'ant', 'tiger', 'parrot'] >>> L1[2] = 'hawk' >>> L1 ['cat', 'dog', 'hawk', 'tiger', 'parrot'] >>> L2 ['cat', 'dog', 'hawk', 'tiger', 'parrot'] - Surprised? This is called an *alias*. Compare it with: :: >>> S1 = 'this is a string' >>> S2 = S1 >>> S1 = 'I changed the first string' >>> S1 'I changed the first string' >>> S2 'this is a string' - Python is designed to do this primarily for reasons of efficiency since - lists can be quite long and are frequently changed - strings tend to be shorter and tend to be fixed - This is true for different data types as well. - assignments create a copy for integers, floats, strings, booleans and tuples. - assignments create an alias for images, lists, sets and dictionaries (which we will see later). - If we want to copy a list we should use a special set of methods. We'll see those next. Aliasing and Function Parameters -------------------------------- - When variables are passed to functions, a copy of their value is created for numbers, strings, booleans: :: def add_two(val1, val2): val1 += val2 return val1 val1 = 10 val2 = 15 print val1, val2 print add_two(val1,val2) print val1, val2 - When lists are passed to functions, the parameter becomes an alias for the argument in the function call. - Formally in computer science, this is known as *pass by reference*. - Here is an example of a function that returns a list containing the two smallest values in its input list: :: def smallest_two(mylist): mylist.sort() newlist = [] if len(mylist) > 0: newlist.append(mylist[0]) if len(mylist) > 1: newlist.append(mylist[1]) return newlist values = [35, 34, 20, 40, 60, 30] print "Before function:", values print "Result of function:", smallest_two(values) print "After function:", values - In class we will discuss what happened For Loops: Writing Operations on List Items ------------------------------------------- - A common operation in programs is to go through every element in a list using a loop. While loops can always be used for this, but a ``for loop`` simplifies this operation significantly. - Let's first go through all the animals in a list, and print them out. :: animals = ['cat', 'monkey', 'hawk', 'tiger', 'parrot'] all_animals = "" index = 1 for animal in animals: animal = animal.capitalize() all_animals += "%d. %s, " %(index, animal) index += 1 print all_animals.strip() - We can understand what is happening by looking at this piece-by-piece: - The keyword ``for`` signals the start of a loop - ``animal`` is a loop variable that takes on the value of each item in the list in the list (as indicated by the keyword ``in``) in succession - The ``:`` signals the start of a block of code that is the “body of the loop” - The body of the loop here is just a single, indented line of code, but in other cases it can be many more. - The end of the loop body is indicated by the blank line - The most important of all, each value in the list is copied to the variable ``animal`` at each step of the for loop. - A word of caution: Do not iterate over list elements with a ``for`` loop to change the elements (unless the elements are containers themselves) or the list (never do this). Or, just avoid this altogether for now. Part 1 Exercise --------------- #. Change the above code to capitalize all the animal names in the list. #. Write a function to capitalize all the names in an input list. #. Write a program to find the number of values greater than the average for the co2_levels given in the following list. :: co2_levels = [ 320.03, 322.16, 328.07, 333.91, 341.47, \ 348.92, 357.29, 363.77, 371.51, 382.47, 392.95 ] #. Suppose you have the following pieces of code. Discuss what is different between the two. :: mylist = [2,8,11] for item in mylist: item *= 2 mylist2 = [ [2], [8], [11] ] for item in mylist: item[0] *= 2 Using ``range`` to create a list of numbers -------------------------------------------- - When you need to index a list, you need to generate numbers to serve as indices. - While solution: :: animals = ['cat', 'monkey', 'hawk', 'tiger', 'parrot'] i = 0 while i < len(animals): print animals[i] i += 1 - With a while loop, you have to be careful not to cause an infinite loop. You can also do the same with a special list of just consecutive numbers. :: >>> range(len(animals)) [0, 1, 2, 3, 4] - Now, we can use the for loop as we have seen to achieve the same result. :: animals = ['cat', 'monkey', 'hawk', 'tiger', 'parrot'] for i in range(len(animals)) print animals[i] - Note: no need to increment a counter anymore. We will see range in more detail when we go over for loops in detail. What Operations Change a List? What Operations Create New Lists? ---------------------------------------------------------------- - Given assignment does not create a copy of a list, what are some methods that allow us to create copies of a list? - Operations that change lists include - sort, insert, append, pop, remove - Operations that create new lists - Slicing, concatenation (``+``), replication (''*``) and ``list()`` - We will see these shortly. Using Indices to “Slice” a List and Create a New List ----------------------------------------------------- - Recall :: >>> co2_levels = [ 320.03, 322.16, 328.07, 333.91, 341.47, 348.92, 357.29, 363.77, 371.51, 382.47, 392.95 ] - Now suppose we just want the values at indices 2, 3 and 4 of this in a new list: >>> three_values = co2_levels[2:5] >>> three_values [328.07, 333.91, 341.47] >>> co2_levels [ 320.03, 322.16, 328.07, 333.91, 341.47, 348.92, 357.29, 363.77, 371.51, 382.47, 392.95 ] - We give the first index and one more than the last index we want - If we leave off the first index, 0 is assumed, and if we leave off the last index, the length of the list is assumed. - Negative indices are allowed — they are just converted to their associated positive values. Some examples: >>> L1 ['cat', 'dog', 'hawk', 'tiger', 'parrot'] >>> L1[1:-1] ['dog', 'hawk', 'tiger'] >>> L1[1:-2] ['dog', 'hawk'] >>> L1[1:-4] [] >>> L1[1:0] [] >>> L1[1:10] ['dog', 'hawk', 'tiger', 'parrot'] More on List Slicing -------------------- - The most general form of slicing involves three values :: L[si:ei:inc] where - ``L`` is the list - ``si`` is the start index - ``ei`` is the end index - ``inc`` is the increment value Any of the three values is optional - We’ll work through some examples in class to - Use slicing to copy an entire list - Use negative indices for slicing - Extracting the even indexed values - Note: ``L[:]`` returns a copy of the whole list of ``L``. This is the same using function ``list(L)``: :: >>> L2 = L1[:] >>> L2[1] = 'monkey' >>> L1 ['cat', 'dog', 'hawk', 'tiger', 'parrot'] >>> L2 ['cat', 'monkey', 'hawk', 'tiger', 'parrot'] >>> L3 = list(L1) >>> L3[1] = 'turtle' >>> L1 ['cat', 'dog', 'hawk', 'tiger', 'parrot'] >>> L2 ['cat', 'monkey', 'hawk', 'tiger', 'parrot'] >>> L3 ['cat', 'turtle', 'hawk', 'tiger', 'parrot'] Concatentation and Replication ------------------------------ - Concatenation: :: >>> v = [1,2,3]+[4,5] >>> v [1,2,3,4,5] - Replication: :: >>> [1]*3 [1,1,1] - These are very similar to the analogous operations with strings. Part 2 Exercises ---------------- #. What is the output of the following? :: x = [6,5,4,3,2,1] + [7]*2 y = x x[1] = y[2] y[2] = x[3] x[0] = x[1] print x y.sort() print x print y #. Write a command to extract values from a list ``L0`` indexed by 0,1,4,7 and 10,11, and return a list containing only these values. #. Write a slicing command to extract values from a list ``L0`` indexed by 1, 4, 7, 10, etc. Converting Strings to Lists --------------------------- - Version 1: use the function ``list`` to create a list of the characters in the string: :: >>> s = "Hello world" >>> t = list(s) >>> print t ['H', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd'] - Use the string ``split`` function, which breaks a string up into a list of strings based on the character provided as the argument. - The default is ``' '``: - Other common splitting characters are ``','``, ``'|'`` and ``'\t'`` - We will play with the ``s = "Hello world"`` example in class. Converting Lists to Strings --------------------------- - What happens when we type the following? :: >>> s = "Hello world" >>> t = list(s) >>> s1 = str(t) This is unlikely to achieve what we want, which is usually the concatention of all of the strings in the list (assumming they are strings). - We will solve this problem using a for loop in the next exercise. Indexing and Slicing Strings ---------------------------- - We can index strings: :: >>> s = "Hello, world!" >>> print s[5] , >>> print s[-1] ! - We can apply all of the slicing operations to strings to create new strings: :: >>> s = "Hello, world!" >>> s[:len(s):2] 'Hlo ol!' - Unlike lists, however, we can not use indexing to replace individual characters in strings: :: >>> s[4] = 'c' Traceback (most recent call last): File "", line 1, in TypeError: 'str' object does not support item assignment Part 3 Exercise --------------- #. Suppose you have the string :: >>> s = "cat | dog | mouse" and you’d like to have the list of strings :: >>> L = [ "cat", "dog", "mouse"] Splitting the list alone does not solve the problem. Instead, you need to use a combination of splitting, and a loop that strips off the extra space characters from each string and appends to the final result. Write this code. It should be at most 4-5 lines of Python. #. Given a list :: >>> L = [ 'cat', 'dog', 'tiger' ] write a line of code to append the string ``'lion'`` #. Rewrite ``L`` so that it is a list of lists, with household pets in the 0th (sub)list, zoo animals in the first. #. How can you append an additional list of farm animals (e.g. ``'horse'``, ``'pig'`` and ``'cow'``) to ``L``. #. Write code to remove ``'tiger'`` from the sublist of zoo animals. Summary ------- - We can write our own functionality to work with lists using ``for`` loops. - Concatentation, replication and slicing create new lists. - Most other list functions that modify a list do so without creating a new list: insert, sort, append, pop, etc. - Assignment of lists and passing a list to a function do NOT create new lists, just aliases of existing lists. - Strings may be indexed and sliced, but indexing may not be used to change a string. - Conversion of a string to a list is accomplished using either ``list`` or ``split`` - Lists can be converted to strings as well, but it takes more work — it is not a natural operation. - Lists can store other lists. Review Exercises: What Does Python Output? ------------------------------------------ #. Without typing into the Python interpreter, find the outputs from the following operations: :: >>> x = ['a','b','c','d', 'e'] >>> print x >>> for item in x: ... print "*%s*" %item, ... >>> print x[3] >>> x[3] = 3 >>> x >>> len(x) >>> x[2]=x[1] >>> x >>> x[5] >>> y = x[1:4] >>> y >>> x #. What about these operations? :: >>> y = [1, 2, 3] >>> y.append('cat') >>> y >>> y.pop() >>> y >>> y.remove(2) >>> y >>> y.remove('cat') >>> z = ['cat','dog'] >>> z.insert(1,'pig') >>> z.insert(0,'ant') >>> z >>> z.sort() >>> z >>> z1 = z[1:3] >>> z1 >>> z #. Write a function that returns a list containing the smallest and largest values in the list that is passed to it as an argument *without changing the list*? Can you think of ways to do this with sorting and without? Hint: use a ``for`` loop.