Lists Here are the bare bones. I will demonstrate lists in class. The next lecture will show lots of functions we can write on lists. The reality of understand lists is understanding the basic operations we can perform on lists. List are most like strings: they contain a sequence of values. In fact, thinking about strings can give us useful insights into the meaning of lists and how they work, while we are learning them. But list, unlike strings, have two properties that make them more interesting (1) the values in a list can be of any type: we can have lists of ints, lists of strings, lists of mixed types, even lists of lists. (2) we can change/mutate the contents of a list, adding, replacing,and removing values List have literals: any number of values (including 0), separated by commas, in brackets: the empty list is written []. So a = [0,1,2,3,4] is a list of numbers; b = ['abc','def','ghi'] is a list of strings; c = [1,'abc',2,3,'xyz'] is a mixed list; d = [1,['abc','def'],3] is a list that contains another list. List operations (again, think about their string equivalents) (1) len: we can compute the length of a list (# of values at the top-level) len(a) is 5; len(b) is 3; len(c) is 5, len(d) is 3 (it has an int, followed by a list, followed by an int: so there are 3 top-level values) (2) Indexing: we can refer to each value in a list by its index, starting at 0 a[0] is 0; b[0] is 'abc'; c[4] is 'xyz', d[1] is ['abc','def'] note that c[4][0] is 'x'; d[1][1] is 'def'; d[1][1][1] is 'e'; d[-1] is 3 note a[10] raises IndexError: list index out of range; recall that a[len(a)] raises an exception: legal indexes are 0 to len(a)-1 (3) Slicing: we can refer to sublists by slicing a[1:] is [1,2,3,4]; a[1:-1] is [1,2,3] (4) Checking containment: the in/not in operators 1 in a is True; 'ghi' in b is True; 5 in c is False; 'abc' in d is False (because in checks values at the top-level of the list. 'abc' in d[1] is True) (5) Catenation: joining two lists to create a new one (think strings) [1,2,3]+['ab','cd'] is [1,2,3,'ab','cd'] a + a is [0,1,2,3,4,,0,1,2,3,4] (just like 'abc'+'abc' is 'abcabc') (6) Multiplication: Think of 3*'abc' as 3 catenations: 'abc' + 'abc' + 'abc' or the result 'abcabcabc' 3 * [0] is [0]+[0]+[0] is [0,0,0] (the most commonly used form of list *) 2 * [1,2] is [1,2,1,2] 2 * d is [1,['abc','def'],3,1,['abc','def'],3] (7) Iterability: for i in a: produces all the top-level values in a (there are len(a) of them): for i in a: print(i,end='') prints: 01234 for i in d: print(i,end='') prints: 1['abc','def']3 for i in d[1]: print(i,end='') prints: abcdef List (mutation) operations (a) Assignment suppose x = [0,1,2,3,4] x[1] = 'a' now x is [0,'a',2,3,4]; the value in index 1 is changed to 'a' x[0] = [10,11] now x is [[10,11],'a',2,3,4]; the value in index 0 is changed to [10,11] in fact, we can even do assignment and slicing (although not used much) suppose x = [0,1,2,3,4] x[1:3] = ['a','b'] now x is [0, 'a', 'b', 3, 4]; the values in index 1-2 have 'a','b' inserted (b) alist.append(avalue) Appends a value at the end of the list: its len increases by 1 an expression: returns None! (see below) print(a,len(a)) [0,1,2,3,4] 5 a.append(5) print(a,len(a)) [0,1,2,3,4,5] 6 Note that alist.append(avalue) is a simpler/faster way to do alist = alist + [avalue] or alist += [avlue] NEVER WRITE l = l.append(value) l is now None (c) del form: del alist[index] or alist[slice] (a statement) a = ['a','b','c','d','e'] del a[2] a is now ['a','b','d','e'] del a[1:-1] a is now ['a','e'] (d) alist.pop(index) Removes the value at a[index] and returns it as the value of this expression print(a,len(a)) ['a','b','c','d','e'] 5 temp = a.pop(2) print(temp,a,len(a) 'c' ['a','b','d','e'] 4 temp = a.pop(2) is equivalent to temp = a[2] followed by del a[2] Critically important code: the following reads in a series of values and puts them i the list, in that order. l = [] while True: x = prompt.for_int('Enter next score (-1 to terminate) if x == -1: break; l.append(x) (e) alist.sort(key,reverse) you must name these parameter if you use them default for key is None; reverse is False l = ['c','e','b','d','a'] l.sort() print(l) l.sort(reverse=True) print(l) prints ['a','b','c','d','e'] ['e','d','c','b','a'] l = ['dog', 'cat', 'mouse', 'frog', 'bird','gerbil', 'fish', 'iguana'] l.sort() print(l) l.sort(reverse=True) print(l) l.sort(key=(lambda x : x[1])) # key uses the 2nd letter in the word print(l) l.sort(key=(lambda x : x[::-1])) # key uses the reverse of the word print(l) prints ['bird', 'cat', 'dog', 'fish', 'frog', 'gerbil', 'iguana', 'mouse'] ['mouse', 'iguana', 'gerbil', 'frog', 'fish', 'dog', 'cat', 'bird'] ['cat', 'gerbil', 'iguana', 'fish', 'bird', 'mouse', 'dog', 'frog'] ['iguana', 'bird', 'mouse', 'dog', 'frog', 'fish', 'gerbil', 'cat'] (f) choice and shuffle: two functions in the random module from random import choice,shuffle print(choice(l)) shuffle(l) print(l) prints (they are based on randomness; your results may vary) dog ['fish', 'gerbil', 'cat', 'mouse', 'bird', 'iguana', 'frog', 'dog'] In fact, we can use the random.randint(low,high) function to write choice ourselves: def choice(alist : list): return alist[ random.randint(0,len(alist)-1 ] Note that if we don't know what kind of values are in a list parameter, we annotate it by just list; if we do know (say int), we annotate it by [int]. ------------------------------------------------------------------------------ Important note about sharing suppose x = [0,1,2,3,4] then we execute z = x now x and z share the same list object if we del x[0], x and z still refer to the same object, but it has mutated and it would print as [1,2,3,4] if instead we wrote z = x[:] z instead refers to a copy of the list x: a new list object, but with the same. if we del x[0], x would print as [1,2,3,4] but z would print as [0,1,2,3,4]: the copy was not mutated Coming: functions that process lists