Answer any questions about the last lab/assignment. You've worked hard, so I thought you deserved a break. You'll still get credit for a full assignment, even though it was only a lab. This lecture: exercising mixtures of data structures. === we have: ints, floats strings, lists, tuples, dictionaries we can combine these in interesting ways! though when they are mixed, it might be confusing how everything fits together. if you are confused at all, write down or enter an example, and figure out how to access what you want that way. For the final exam, need to know what the data structure is from these types of descriptions a list of strings a list of lists dictionary indexed by strings with lists as values etc. To make things simple, let's use ints. for strings, just use 2-char strings like 'jj', 'kk', etc. also, let's just use variables x, y, z !!! do this so you can also write on the board. !!! Tell them: I will save this session on the schedule. !!! or, at least, the one I already saved before class (I ran through it already) >>> # Quiz: write down a list of lists ... >>> x = [[4,5],[3],[4,5,6]] >>> len(x) 3 >>> x[1] [3] >>> x[0] [4, 5] >>> x[2] [4, 5, 6] >>> x[:1] [[4, 5]] >>> x[1:] [[3], [4, 5, 6]] >>> y = [9,4] >>> x.append(y) >>> x [[4, 5], [3], [4, 5, 6], [9, 4]] >>> len(x) 4 >>> x[3] [9, 4] >>> x[2][0] 4 >>> >>> # + takes two sequences and puts them together ... >>> # for lists, think about this as removing the inside ... # parens ... >>> [1,2,3] + [4,5,6] [1, 2, 3, 4, 5, 6] >>> x [[4, 5], [3], [4, 5, 6], [9, 4]] >>> y [9, 4] >>> x + y [[4, 5], [3], [4, 5, 6], [9, 4], 9, 4] >>> >>> # The empty list is SOMETHING ... >>> y [9, 4] >>> y.append([]) >>> y [9, 4, []] >>> len(y) 3 >>> y[2] [] >>> # Quiz write down a list of strings >>> # list of strings ... >>> x = ["jj","kk","ll"] >>> len(x) 3 >>> len(x[0]) 2 >>> y = ["a","b"] >>> x + y ['jj', 'kk', 'll', 'a', 'b'] >>> x[0] + y[1] 'jjb' >>> x.append(x[0] + y[1]) >>> x ['jj', 'kk', 'll', 'jjb'] >>> >>> # "" is something - the empty string ... >>> x.append("") >>> x ['jj', 'kk', 'll', 'jjb', ''] >>> len(x) 5 >>> # Quiz - write down a list of lists of strings ... >>> x = [[],["jj","kk"],["a"]] >>> len(x) 3 >>> x[0] [] >>> x[1] ['jj', 'kk'] >>> x[2] ['a'] >>> len(x[1]) 2 >>> x = x + [["tt","ww","xx"]] >>> x [[], ['jj', 'kk'], ['a'], ['tt', 'ww', 'xx']] >>> len(x) 4 >>> x.append(["hi","there","bear"]) >>> x [[], ['jj', 'kk'], ['a'], ['tt', 'ww', 'xx'], ['hi', 'there', 'bear']] >>> # Quiz: write a loop that creates one big string from the ... # strings stored in x. ... >>> # we'll call the new string bigstr. ... >>> bigstr = "" >>> for l in x: ... for s in l: ... bigstr += s ... >>> bigstr 'jjkkattwwxxhitherebear' >>> # trace it on the board ... >>> #let's add print strings to understand the code ... >> #and, let's work with an easier example x = [["aa","bb"],["cc"],[],["dd","ee"]] >>> bigstr = "" >>> for l in x: ... print("working on list",l) ... for s in l: ... print("bigstr so far:",bigstr,"|") ... print("s:",s) ... bigstr += s ... print("bigstr after adding",s,":",bigstr) >>> # Quiz: define a dictionary whose keys are strings and whose values are ints ... >>> x = {"jj":4,"kk":5,"zz":7} >>> x {'kk': 5, 'zz': 7, 'jj': 4} >>> # does this make sense? x[4]? ... >>> x[4] Traceback (most recent call last): File "", line 1, in KeyError: 4 >>> #how do we get at the 4? ... >>> x["jj"] 4 >>> # Write code to print each key and its values ... >>> for k in x: ... print(k,x[k]) ... kk 5 zz 7 jj 4 >>> # write x on board, make sure they see the pieces ... >>> # but what if we want to print them in alphabetical ... # order by key? ... >>> #first, create a list of the keys ... >>> keys = list(x.keys()) >>> keys ['kk', 'zz', 'jj'] >>> type(keys) >>> dir(list) ['__add__', '__class__', '__contains__', '__delattr__', '__delitem__', >>> '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', >>> '__getitem__', '__gt__', '__hash__', '__iadd__', '__imul__', >>> '__init__', '__iter__', '__le__', '__len__', '__lt__', '__mul__', >>> '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', >>> '__reversed__', '__rmul__', '__setattr__', '__setitem__', >>> '__sizeof__', '__str__', '__subclasshook__', 'append', 'count', >>> 'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort'] >>> #see the sort? ... >>> help(list.sort) Help on method_descriptor: sort(...) L.sort(key=None, reverse=False) -- stable sort *IN PLACE* >>> keys.sort() >>> keys ['jj', 'kk', 'zz'] >>> # now, let's print ... >>> for k in keys: ... print(k,x[k]) ... jj 4 kk 5 zz 7 >>> >>> # reminder about the functions that convert between types. Python ... # will do the conversion if it can make sense of it. ... >>> float("3") 3.0 >>> float(3) 3.0 >>> int("34") 34 >>> str(34) '34' >>> str(54.3) '54.3' >>> list("hello there bear") ['h', 'e', 'l', 'l', 'o', ' ', 't', 'h', 'e', 'r', 'e', ' ', 'b', 'e', 'a', 'r'] >>> list("54.3") ['5', '4', '.', '3'] >>> >>> list("hello there bear") ['h', 'e', 'l', 'l', 'o', ' ', 't', 'h', 'e', 'r', 'e', ' ', 'b', 'e', 'a', 'r'] >>> list("54.3") ['5', '4', '.', '3'] >>> >>> >>> >>> #remember our dictionary x? ... >>> x {'kk': 5, 'zz': 7, 'jj': 4} >>> x.keys() dict_keys(['kk', 'zz', 'jj']) >>> list(x.keys()) ['kk', 'zz', 'jj'] >>> >>> # write code to sum the numbers stored in x ... >>> x {'kk': 5, 'zz': 7, 'jj': 4} >>> sum = 0 >>> for k in x: ... sum += x[k] ... >>> sum 16 >>> >>> # quiz: define a dictionary whose keys are strings ... # and whose values are lists of ints ... >>> x = {"kk":[1,2,3],"jj":[0],'ll':[]} >>> x {'kk': [1, 2, 3], 'll': [], 'jj': [0]} >>> x['kk'] [1, 2, 3] >>> len(x['jj']) 1 >>> len(x['ll']) 0 >>> x['jj'] + x['kk'] [0, 1, 2, 3] >>> x['ll'] [] >>> x['ll'].append(54) >>> x {'kk': [1, 2, 3], 'll': [54], 'jj': [0]} >>> x['ll'].append(33) >>> x {'kk': [1, 2, 3], 'll': [54, 33], 'jj': [0]} >>> len(x['ll']) 2 >>> # write code to sum all the ints stored in x >>> sum = 0 >>> for k in x: ... for i in x[k]: ... sum += i ... >>> sum 93 >>> #trace that for the first few. === >>> # one thing to review about Python - that it let's you do things like this ... >>> one,two = [1,2] >>> one 1 >>> two 2 >>> one,two = [1,2,3] Traceback (most recent call last): File "", line 1, in ValueError: too many values to unpack (expected 2) >>> #Python makes sense of it if it can ==== Now, let's define data structures that make sense, and practice accessing them. Go back to the phone numbers! # you have to study this for the exam anyway; let's help you out in class today. [phoneDictEG.py - so I don't have to type it in again] Show them the file: phone = {'555-7632': 'Paul', '555-9832': 'Andrew',\ '555-6677': 'Jen', '555-9823': 'Michael',\ '555-6342' : 'Wael', '555-7343' : 'Paul',\ '555-2222' : 'Michael'} >>> from phoneDictEG import phone # for those who are interested, # you can do this, and then you don't have to say # phoneDictEG.phone # You don't have to know this, though >>> phone {'555-7632': 'Paul', '555-9832': 'Andrew', '555-7343': 'Paul', '555-9823': 'Michael', '555-6342': 'Wael', '555-6677': 'Jen', '555-2222': 'Michael'} >>> # So, we have a dictionary where the keys and values are both strings ... >>> phone.keys() dict_keys(['555-7632', '555-9832', '555-7343', '555-9823', '555-6342', '555-6677', '555-2222']) >>> phone.items() dict_items([('555-7632', 'Paul'), ('555-9832', 'Andrew'), ('555-7343', 'Paul'), ('555-9823', 'Michael'), ('555-6342', 'Wael'), ('555-6677', 'Jen'), ('555-2222', 'Michael')]) >>> phone['555-7632'] 'Paul' >>> len(phone['555-7632']) # be careful - maybe tricky! 4 >>> >>> #what's wrong with this? ... >>> len(phone['555-7632]) # be careful - maybe tricky! File "", line 1 len(phone['555-7632]) # be careful - maybe tricky! ^ SyntaxError: EOL while scanning string literal >>> #missing close '! >>> phone {'555-7632': 'Paul', '555-9832': 'Andrew', '555-7343': 'Paul', '555-9823': 'Michael', '555-6342': 'Wael', '555-6677': 'Jen', '555-2222': 'Michael'} >>> len(phone) 7 >>> # Paul's phone numbers ... >>> # note there are 2 ... >>> # Quiz: write code to find Paul's phone numbers ... >>> for k in phone: ... if phone[k] == "Paul" File "", line 2 if phone[k] == "Paul" >>> # Paul's phone numbers ... >>> # note there are 2 ... >>> # Quiz: write code to find Paul's phone numbers ... >>> for k in phone: ... if phone[k] == "Paul" File "", line 2 if phone[k] == "Paul" # oops, what do we do now? We are supposed # to be gathering up Paul's phone numbers. # if the if is true, then .. what are we adding # this number to? # start over >>> nums = [] >>> for k in phone: ... if phone[k] == "Paul": ... nums.append(phone[k]) ... >>> nums ['Paul', 'Paul'] >>> # oops - what did we do wrong? ... >>> >> # try again! ... >>> nums = [] >>> for k in phone: ... if phone[k] == "Paul": ... nums.append(k) ... >>> nums ['555-7632', '555-7343'] >>> #ok, good >>> # remember, here is our list ... >>> phone {'555-7632': 'Paul', '555-9832': 'Andrew', '555-7343': 'Paul', '555-9823': 'Michael', '555-6342': 'Wael', '555-6677': 'Jen', '555-2222': 'Michael'} >>> #let's create a new dictionary that is indexed by person ... >>> # it's common to have multiple dictionaries containing the same data in different ... # forms. you might need to access the information differently for different purposes ... >>> #what does that mean? ... >>> #QUIZ: what will the keys be? Write down one of the keys ... >>> 'Paul' #etc 'Paul' >>> #QUIZ: the values will be what type? ... >>> # string, e.g., '555-9832' ... >>> # no - some people have more than one phone number! ... >>> #remember, here are Paul's phone numbers ... >>> nums ['555-7632', '555-7343'] >>> #so, the values are lists of ... ... >>> # the values are lists of strings ... >>> #for example, phone['Paul'] should be ... >>> nums ['555-7632', '555-7343'] >>> >>> phone {'555-7632': 'Paul', '555-9832': 'Andrew', '555-7343': 'Paul', '555-9823': 'Michael', '555-6342': 'Wael', '555-6677': 'Jen', '555-2222': 'Michael'} >>> #what should phone['Andrew'] be? ... >>> ['555-7343'] ['555-7343'] >>> phoneByName = {} # this is how you create an empty dict >>> # some reminders ... >>> phone.items() dict_items([('555-7632', 'Paul'), ('555-9832', 'Andrew'), ('555-7343', >>> 'Paul'), ('555-9823', 'Michael'), ('555-6342', 'Wael'), >>> ('555-6677', 'Jen'), ('555-2222', 'Michael')]) >>> number,name = ('555-6677','Jen') >>> number '555-6677' >>> name 'Jen' >>> if 'Jen' in phoneByName: ... print('yes') ... else: ... print('no') ... no >>> phoneByName {} >>> #ok! ... >>> if 'Jen' in phone: ... print('yes') ... else: ... print('no') ... no >>> phone {'555-7632': 'Paul', '555-9832': 'Andrew', '555-7343': 'Paul', >>> '555-9823': 'Michael', '555-6342': 'Wael', '555-6677': 'Jen', >>> '555-2222': 'Michael'} >>> if '555-7632' in phone: ... print('yes') ... else: ... print('no') ... yes >>> #ok, just messing with you, to remind you what 'in' means ... >>> # so, we are building a dictionary indexed by name, with values ... # the list of phone numbers for that person ... >>> phone {'555-7632': 'Paul', '555-9832': 'Andrew', '555-7343': 'Paul', >>> '555-9823': 'Michael', '555-6342': 'Wael', '555-6677': 'Jen', >>> '555-2222': 'Michael'} #!!! make sure the following stay up so I can trace it on the board. >>> phone.items() dict_items([('555-7632', 'Paul'), ('555-9832', 'Andrew'), ('555-7343', >>> 'Paul'), ('555-9823', 'Michael'), ('555-6342', 'Wael'), >>> ('555-6677', 'Jen'), ('555-2222', 'Michael')]) >>> for number,name in phone.items(): ... if name in phoneByName: ... phoneByName[name].append(number) ... else: ... phoneByName[name] = [number] ... >>> phoneByName {'Jen': ['555-6677'], 'Paul': ['555-7632', '555-7343'], 'Wael': ['555-6342'], 'Michael': ['555-9823', '555-2222'], 'Andrew': ['555-9832']} #### TRACE ON BOARD!! phoneByName = {} number 555-7632 name Paul else: phoneByName['Paul'] = ['555-7632'] number 555-9832 name Andrew else: phoneByName['Andrew'] = ['555-9832'] number '555-7343' name 'Paul' if: phoneByName['Paul'].append('555-7343') now: phoneByName['Paul'] is ['555-7632','555-7343'] [recall: inverted_dict.py already on the schedule] >>> from dict_of_dicts import * >>> db {'rfranklin': {'born': 1920, 'notes': 'contributed to discovery of >>> DNA', 'surname': 'Franklin', 'died': 1957, 'forename': >>> 'Rosalind'}, 'rcarson': {'surname': 'Carson', 'author': ['Silent >>> Spring'], 'notes': 'raised awareness of effects of DDT', 'born': >>> 1907, 'forename': 'Rachel', 'died': 1964}, 'jgoodall': {'surname': >>> 'Goodall', 'author': ['In the Shadow of Man', 'The Chimpanzees of >>> Gombe'], 'notes': 'primate researcher', 'born': 1934, 'forename': >>> 'Jane', 'died': None}} A database - an organized collection of data. Like dictionaries, you look things up in a database according to a key. Say, an ID. We can use dictionaries for simple databases. This is something you could do if you program for your own purposes. keys: say, first initial, last name For each entry, we store different pieces of information. some simple strings: born, notes, two name fields. but we can also have lists as values. the list of boods for which the person is an author. >>> db.keys() dict_keys(['rfranklin', 'rcarson', 'jgoodall']) >>> db['rcarson'] {'surname': 'Carson', 'author': ['Silent Spring'], 'notes': 'raised awareness of effects of DDT', 'born': 1907, 'forename': 'Rachel', 'died': 1964} >>> # what books is jgoodall the author of? ... >>> db['jgoodall'] {'surname': 'Goodall', 'author': ['In the Shadow of Man', 'The Chimpanzees of Gombe'], 'notes': 'primate researcher', 'born': 1934, 'forename': 'Jane', 'died': None} >>> db['jgoodall']['author'] ['In the Shadow of Man', 'The Chimpanzees of Gombe'] >>> # when was she born? ... >>> db['jgoodall']['born'] 1934 >>> # note that there are different fields in different entries. rfranklin didn't author any books, .e.g. ... >>> # for the entire database, print all the books authored by people ... # If someone is not an author, print that ... >>> for k in db: ... if 'author' in db[k].keys(): ... print(k,db[k]["author"]) ... else: ... print(k,"is not an author") ... rfranklin is not an author rcarson ['Silent Spring'] jgoodall ['In the Shadow of Man', 'The Chimpanzees of Gombe'] >>> def pp(first,last,books): ... print(first,last,end="") ... if books: ... print(" is the author of the following books:") ... for b in books: ... print(b) ... else: ... print(" is not an author") ... This isn't quite right: >>> db {'rfranklin': {'born': 1920, 'notes': 'contributed to discovery of DNA', 'surname': 'Franklin', 'died': 1957, 'forename': 'Rosalind'}, 'rcarson': {'surname': 'Carson', 'author': ['Silent Spring'], 'notes': 'raised awareness of effects of DDT', 'born': 1907, 'forename': 'Rachel', 'died': 1964}, 'jgoodall': {'surname': 'Goodall', 'author': ['In the Shadow of Man', 'The Chimpanzees of Gombe'], 'notes': 'primate researcher', 'born': 1934, 'forename': 'Jane', 'died': None}} >>> for k in db: ... pp(db[k]['forename'],db[k]['surname'],db[k]['author']) ... Traceback (most recent call last): File "", line 2, in KeyError: 'author' >>> for k in db: ... if 'author' in db[k]: ... pp(db[k]['forename'],db[k]['surname'],db[k]['author']) ... else: ... pp(db[k]['forename'],db[k]['surname'],[]) ... Rosalind Franklinis not an author Rachel Carsonis the author of the following books: Silent Spring Jane Goodallis the author of the following books: In the Shadow of Man The Chimpanzees of Gombe === Next time: wannabe.py - go over it piece by piece