# coding: utf-8 # ## There are four main types of collections of data ("Sequence objects") ## # # • Lists: a mutable array of data # • Tuples: ordered, immutable list # • Sets: unordered collection of unique elements # • Dictionaries: keyword/value lookup # # The value in each element can be whatever (type) you want. # > string is actually a sequence object # ### List ### # #### denoted with a brackets #### # In[1]: v = [1,2,3] ; print len(v), type(v) # In[2]: v[0:2] # In[3]: v = ["eggs","spam",-1,("monty","python"),[-1.2,-3.5]] len(v) # In[4]: v[0] ="green egg" v[1] += ",love it." v[-1] # In[5]: v[-1][1] = None ; print v # In[6]: v = v[2:] ; print v # In[7]: # let's make a proto-array out of nested lists vv = [ [1,2], [3,4] ] # In[8]: print len(vv) # In[9]: determinant = vv[0][0]*vv[1][1] - vv[0][1]*vv[1][0] print determinant # the main point here: lists are **changeable** ("mutable") # ### lists can be extended & appended ### # In[10]: v = [1,2,3] v.append(4) v.append([-5]) ; print v # > Lists can be considered objects. # **Objects** are like animals: they know how to do stuff (like eat and sleep), they know how to interact with others (like make children), and they have characteristics (like height, weight). # # > "Knowing how to do stuff" with itself is called a method. In this case "append" is a method which, when invoked, is an action that changes the characteristics (the data vector of the list itself). # In[11]: v = v[:4] w = ['elderberries', 'eggs'] v + w # In[12]: v.extend(w) ; print v # In[13]: v.pop() # In[14]: print v # In[15]: v.pop(0) ; print v ## pop the first element # * `.append()`: adds a new element # * `.extend()`: concatenates a list/element # * `.pop()`: remove an element # #### lists can be searched, sorted, & counted #### # In[16]: v = [1,3, 2, 3, 4, 'elderberries'] v.sort() ; print v # `reverse` is a keyword of the `.sort()` method # In[17]: v.sort(reverse=True) ; print v # `.sort()` changes the the list in place # In[18]: v.index(4) ## lookup the index of the entry 4 # In[19]: v.index(3) # In[20]: v.count(3) # In[21]: v.insert(0,"it's full of stars") ; print v # In[22]: v.remove(1) ; print v #   # ### IPython is your new best friend ## # # 1. Type `v.` then the Tab button # # 2. Type `v.re` then the Tab button # # 3. Type `v.remove?` # In[23]: ## try it here #   # ### List ### # #### iteration #### # In[24]: a = ['cat', 'window', 'defenestrate'] for x in a: print x, len(x) # In[25]: for i,x in enumerate(a): print i, x, len(x) # In[26]: for x in a: print x, # The syntax for iteration is... # # for variable_name in iterable: # # do something with variable_name # The `range()` function # In[27]: x = range(4) ; print x total = 0 for val in range(4): total += val print "By adding " + str(val) + " the total is now " + str(total) # # `range`([`start`,] `stop`[, `step`]) # → list of integers # In[28]: total = 0 for val in range(1,10,2): total += val print "By adding " + str(val) + " the total is now " + str(total) # In[29]: a = ['Mary', 'had', 'a', 'little', 'lamb'] for i in range(len(a)): print i, a[i] #   # ### Tuple ### # denoted with parentheses # In[30]: t = (12,-1) print type(t) # In[31]: print isinstance(t,tuple) print len(t) # In[32]: t = (12,"monty",True,-1.23e6) print t[1] # In[33]: print t[-1] # In[34]: t[-2:] # get the last two elements, return as a tuple # In[35]: x = (True) ; print type(x) x = (True,) ; print type(x) # In[36]: type(()), len(()) # In[37]: type((,)) # single-element tuples look like `(element,)` # cannot change a tuple # but you can create new one with concatenation # In[38]: t[2] = False # In[39]: t[0:2], False, t[3:] # In[40]: ## the above is not what we wanted... need to concatenate t[0:2] + False + t[3:] # In[41]: y = t[0:2] + (False,) + t[3:] ; print y # In[42]: t*2 #   # ### Casting Back and Forth ### # In[43]: a = [1,2,3,("b",1)] # In[44]: b = tuple(a) ; print b # In[45]: print list(b) # In[46]: set(a) # In[47]: list(set("spam")) # > casting only affects top-level structure, not the elements # #### Why use tuples when you have lists? #### # In[48]: # A tuple is something that you probably don’t want changed continents = ("North America", "South America", "Europe", "Asia", "Australia", "Antarctica") # Something you might want to add and subtract from tasks = ["learn Python","eat dinner","climb Mt. Everest"] # In[49]: # something you probably don't want in your tasks... tasks.append("find Atlantis") print tasks # In[50]: # tuples are immutable! continents.append("Atlantis") # In[51]: first_name, last_name = "Jack", "Hewitt" # This is a tuple assignment print "My name is", first_name, last_name # This statement prints a tuple # In[52]: # This function returns a tuple (more on this later…) import cmath r,phi = cmath.polar(-1.); print r,phi # ### Sets ### # #### denoted with a curly braces #### # In[53]: {1,2,3,"bingo"} # In[54]: print type({1,2,3,"bingo"}) # In[55]: print type({}) # In[56]: print type(set()) # In[57]: set("spamIam") # sets have unique elements. They can be # compared, differenced, unionized, etc. # In[58]: a = set("sp"); b = set("am"); print a ; print b # In[59]: c = set(["a","m"]) c == b # In[60]: "p" in a # In[61]: "ps" in a # In[62]: q = set("spamIam") a.issubset(q) # In[63]: a | b # In[64]: q - (a | b) # In[65]: q & (a | b) # Like lists, we can use as (unordered) buckets # `.pop()` gives us a random element # In[66]: # this is pretty volitile...wont be the same # order on all machines for i in q & (a | b): print i, # In[67]: q.remove("a") # In[68]: q.pop() # In[69]: print q.pop() print q.pop() # In[29]: print q.pop() # In[30]: q.pop() #   # ## Dictionaries ## # denoted with a curly braces and colons # In[72]: d = {"favorite cat": None, "favorite spam": "all"} # these are key: value, key: value, ... # In[73]: print d["favorite cat"] d[0] ## this is not a list and you dont have a keyword = 0 # In[74]: e = {"favorite cat": None, "favorite spam": "all", 1: 'loneliest number'} e[1] == 'loneliest number' # dictionaries are **UNORDERED***. # >You cannot assume that one key comes before or after another # # * you can use a special type of ordered dict if you really need it: # # http://docs.python.org/whatsnew/2.7.html#pep-372-adding-an-ordered-dictionary-to-collections # ### 4 ways to make a Dictionary ### # In[75]: # number 1...you've seen this d = {"favorite cat": None, "favorite spam": "all"} # In[76]: # number 2 d = dict(one = 1, two=2,cat = 'dog') ; print d # In[77]: # number 3 ... just start filling in items/keys d = {} # empty dictionary d['cat'] = 'dog' d['one'] = 1 d['two'] = 2 d # In[78]: # number 4... start with a list of tuples mylist = [("cat","dog"), ("one",1),("two",2)] print dict(mylist) # In[79]: dict(mylist) == d #   # ### Dictionaries: they can be complicated (in a good way) ### # In[80]: d = {"favorite cat": None, "favorite spam": "all"} # In[81]: d = {'favorites': {'cat': None, 'spam': 'all'}, 'least favorite': {'cat': 'all', 'spam': None}} print d['least favorite']['cat'] # remember: the backslash (\) allows you to across break lines. Not technically needed when defining a dictionary or list # In[82]: phone_numbers = {'family': [('mom','642-2322'),('dad','534-2311')], 'friends': [('Sylvia','652-2212')]} # In[83]: for group_type in ['friends','family']: print "Group " + group_type + ":" for info in phone_numbers[group_type]: print " ",info[0], info[1] # In[84]: # this will return a list, but you dont know in what order! phone_numbers.keys() # In[85]: phone_numbers.values() #   # `.keys()` and `.values()`: are called `methods` on dictionaries # In[86]: for group_type in phone_numbers.keys(): print "Group " + group_type + ":" for info in phone_numbers[group_type]: print " ",info[0], info[1] # we cannot ensure ordering here of the groups # In[87]: groups = phone_numbers.keys() groups.sort() for group_type in groups: print "Group " + group_type + ":" for info in phone_numbers[group_type]: print " ",info[0], info[1] # `.iteritems()` is a handy method, # returning key,value pairs with each iteration # In[88]: for group_type, vals in phone_numbers.iteritems(): print "Group " + group_type + ":" for info in vals: print " ",info[0], info[1] # Some examples of getting values: # In[89]: phone_numbers['co-workers'] # In[90]: phone_numbers.has_key('co-workers') # In[91]: print phone_numbers.get('co-workers') # In[92]: phone_numbers.get('friends') == phone_numbers['friends'] # In[93]: print phone_numbers.get('co-workers',"all alone") #   # ### setting values ### # # you can edit the values of keys and also `.pop()` & `del` to remove certain keys # In[94]: # add to the friends list phone_numbers['friends'].append(("Jeremy","232-1121")) print phone_numbers # In[95]: ## Sylvia's number changed phone_numbers['friends'][0][1] = "532-1521" # In[96]: phone_numbers['friends'][0] = ("Sylvia","232-1521"); print phone_numbers['friends'] # In[97]: ## I lost all my friends preparing for this Python class phone_numbers['friends'] = [] # sets this to an empty list # In[98]: ## remove the friends key altogether print phone_numbers.pop('friends') # In[99]: print phone_numbers # In[100]: del phone_numbers['family'] # In[101]: print phone_numbers #   # `.update()` method is very handy, like `.append()` for lists # In[102]: phone_numbers.update({"friends": [("Sylvia's friend, Dave", "532-1521")]}) print phone_numbers #   # ## List Comprehension ## # # You can create lists "on the fly" by asking simple questions of other iterateable data structures # example: I want a list of all numbers from 0 - 100 whose lowest two bits are both one (e.g., 3, 7, ...) but is not divisible by 11 # In[103]: mylist = [] for num in range(101): if (num & 2) and (num & 1) and (num % 11 != 0.0): mylist.append(num) print mylist # In[104]: mylist=[num for num in range(101) if (num & 2) and (num & 1) and (num % 11 != 0.0)] print mylist # example: I want a list of all mesons whose masses are between 100 and 1000 MeV # In[33]: particles = [{"name":"π+" ,"mass": 139.57018}, {"name":"π0" ,"mass": 134.9766}, {"name":"η5" ,"mass": 47.853}, {"name":"η′(958)","mass": 957.78}, {"name":"ηc(1S)", "mass": 2980.5}, {"name": "ηb(1S)","mass": 9388.9}, {"name":"K+", "mass": 493.677}, {"name":"K0" ,"mass": 497.614}, {"name":"K0S" ,"mass": 497.614}, {"name":"K0L" ,"mass": 497.614}, {"name":"D+" ,"mass": 1869.62}, {"name":"D0" ,"mass": 1864.84}, {"name":"D+s" ,"mass": 1968.49}, {"name":"B+" ,"mass": 5279.15}, {"name":"B0" ,"mass": 5279.5}, {"name":"B0s" ,"mass": 5366.3}, {"name":"B+c" ,"mass": 6277}] # data source: http://en.wikipedia.org/wiki/List_of_mesons my_mesons = [ (x['name'],x['mass']) for x in particles if x['mass'] <= 1000.0 and x['mass'] >= 100.0] # In[34]: # get the average tot = 0.0 for x in my_mesons: tot += x[1] print "The average meson mass in this range is " + str(tot/len(my_mesons)) + " MeV/c^2." # In[35]: my_mesons[0][0] # In[36]: print my_mesons[0][0] #   # ## Breakout 2## # Consider the following data detailing Tuesday meetings at Goddard (file: [meetings.py](https://github.com/kialio/python-bootcamp/blob/master/DataFiles_and_Notebooks/02_AdvancedDataStructures/meetings.py).): # # organizers = { "Extragalactic Journal Club": "Alaina Henry", "Gamma-Ray Burst Lunch": "Judy Racusin", "Astrophysics Colloquium": "Jeremy Schnittman", "Exoplanet Club": "Margaret Pan", "Python Users Group": "Terri Brandt", "IS&T Colloquium Series": "Ben Kobler", "NGAPS Happy Hour": "Toni Venters" } # # # includes the meeting, room, day, start time(decimal hours), end time # meetings = [("Gamma-Ray Burst Lunch","B34 E256","Tue",12.0,13.0),\ # ("Extragalactic Journal Club","B34 S391","Tue",14.0,15.0), \ # ("Python Users Group","B34 W120A/B","Tue",14.5,15.5), \ # ("Astrophysics Colloquium","B34 E215","Tue",15.5,17.0), \ # ("NGAPS Happy Hour","B34 E215","Tue",17.0,18.0), \ # ("Exoplanet Club","B34 E215","Tue",11.5,12.5), \ # ("IS&T Colloquium Series","B3 Auditorium","Tue",11.0,12.0) ] # # # Complete the following 2 tasks: # # 1. Print out a schedule organized by meeting name. # 2. Print out a schedule organized by time. (Hint: You'll need to do a manual sorting on the last element of each flight element, before beginning the printing loop.) # # Example schedule organized by time: # # Meeting Room No. Day Time Organizer # ------------------------------------------------------------------------------- # IS&T Colloquium Series B3 Auditorium Tue 11.0 Ben Kobler # Exoplanet Club B34 E215 Tue 11.5 Margaret Pan # Gamma-Ray Burst Lunch B34 E256 Tue 12.0 Judy Racusin # ... # In[38]: ## try it here # Done? For extra credit: print out a schedule organized by time including meetings on a different day. # # organizers = { "Extragalactic Journal Club": "Alaina Henry", "Gamma-Ray Burst Lunch": "Judy Racusin",\ # "Astrophysics Colloquium": "Jeremy Schnittman", "Exoplanet Club": "Margaret Pan",\ # "Python Users Group": "Terri Brandt", "IS&T Colloquium Series": "Ben Kobler",\ # "NGAPS Happy Hour": "Toni Venters", "Engineering Colloquium": "Brent Warner", \ # "SEAL Talk": "Deborah Padgett", "SED Director's Seminar": "Diane Elben", \ # "Fermi Journal Club": "David Green", "Goddard Scientific Colloquium": "David Thompson" } # # # includes the meeting, room, day, start time(decimal hours), end time # meetings = [("Gamma-Ray Burst Lunch","B34 E256","Tue",12.0,13.0), \ # ("Extragalactic Journal Club","B34 S391","Tue",14.0,15.0), \ # ("Python Users Group","B34 W120A/B","Tue",14.5,15.5), \ # ("Astrophysics Colloquium","B34 E215","Tue",15.5,17.0), \ # ("NGAPS Happy Hour","B34 E215","Tue",17.0,18.0), \ # ("Exoplanet Club","B34 E215","Tue",11.5,12.5), \ # ("Fermi Journal Club","B34 E256","Wed",15.5,16.5),\ # ("SEAL Talk","B34 E215","Thu",12.0,13.5), \ # ("SED Director's Seminar","B33 H114","Fri",12.0,13.0), \ # ("Engineering Colloquium","B3 Auditorium","Mon",15.5,16.5), \ # ("Goddard Scientific Colloquium","B3 Auditorium","Fri",15.5,16.5), \ # ("IS&T Colloquium Series","B3 Auditorium","Tue",11.0,12.0) ] # # In[39]: ## try it here # adapted from the UC Berkeley Python Bootcamp by J Bloom #