# Lecture notes 2/3/2021 ## Ranges ```python= # # declaring ranges # with just 1 argument, it will assume a start of 0 nums = range(5) print(nums) # => Range(0,5) print(list(nums)) # => [0,1,2,3,4] # if the start value is a greater number than the stop, the # range is empty nums = range(-5) print(list(nums)) # => [] # the range will include the "start" number and exclude the "stop" nums_range = range(1, 11) print(list(nums_range)) # => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] # an optional third parameter will control step size fives = range(0, 51, 5) print(list(fives)) # => [0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50] # step size can be negative test = range(50, 4, -5) print(list(test)) # => [50, 45, 40, 35, 30, 25, 20, 15, 10, 5] # loops with ranges my_range = range(5) for i in my_range: print(i) for i in range(1, 10, 2): print(i) items = ['apple', 'banana', 'cherry'] for i in range(len(items)): print(i, items[i]) for i in items: print(i) ``` # Dictionaries ```python= # Dictionaries # ordered and mutable # pairs of keys and values # keys must be "hashable" (immutable) # e.g. strings, numbers, tuples, booleans # declaring: use curly braces # notice that unlike JS objects, keys do not have to be strings # but keys that are strings must use quotes my_dict = { "word": "cooool", 1: "one", False: 42, ("tuple", "keys"): ["lists", "can", "be", "values", "not", "keys"], None: {"key": "value"} } print(my_dict) # => { # 'word': 'cooool', # 1: 'one', # False: 42, # ('tuple', 'keys'): ['lists', 'can', 'be', 'values', 'not', 'keys'], # None: {'key': 'value'} # } # length is the number of key:value pairs print(len(my_dict)) # => 5 # accessing an individal value by key print(my_dict[None]) # => {'key': 'value'} # add/remove items del my_dict[False] print(my_dict) my_dict["key"] = "value" print(my_dict) my_dict["key"] = "different value" print(my_dict) # # in JS can use dot or bracket notation for accessing values in objects # console.log(my_dict.word) # console.log(my_dict["word"]) # Python doesn't use dot notation for dictionaries! print(my_dict["word"]) print(my_dict.word) # AttributeError: 'dict' object has no attribute 'word' # in JavaScript, attempting to access a value that doesn't exist will # just return undefined # in python this will throw an error print(my_dict["nope"]) # => KeyError: 'nope' # you can use the get() method to safely access a key that may not exist print(my_dict.get("nope", "yep")) # => "yep" # conditionals with dictionaries if "word" in my_dict: print("word key exists") # loops with dictionaries for key in my_dict: print(key, my_dict[key]) for key, value in my_dict.items(): print("key:", key, "value:", value) # dict() can be used to define dictionaries using keyword args # the keys can only be strings though user = dict( name="Marnie", email="marnie@marnie.com", friends=["Bonnie", "Sammie", "Lexie"], ) print(user) # dict() can also turn a list of tuples into a dict list_of_tuples = [ ("name","Bonnie"), ("email", "bonnie@bonnie.com"), ("friends", ["Marnie", "Sammie"]), ] user2 = dict(list_of_tuples) print(user2) # # zip() keys = ["peanut butter", "sugar", "egg"] values = ["1 cup", "1 cup", 1] recipe = dict(zip(keys, values)) print(recipe) # digression: # reassigning values vs mutability # tuples are immutable, so you cannot modify them. however, you can still # reassign the variable. # this changes what location in memory the variable is pointing to. # but the tuple itself is not changing # you can illustrate this by checking the unique id of a variable # before and after reassigning it my_tuple = ("some stuff", "more") print(id(my_tuple)) # => some long id number my_tuple = 5 print(id(my_tuple)) # => a new long id number # changing the contents of a list by appending to it will not change the id. # it's still the same object! my_list = ["hey"] print(id(my_list)) # => some long id number my_list.append("stuff") print(id(my_list)) # => the same long id number ``` # Sets ## Set operations visualized ### Union `(a | b)` ![](https://i.imgur.com/5bY2S1u.png) ### Intersection `(a & b)` ![](https://i.imgur.com/dyvvZAv.png) ### Symmetric difference `(a ^ b)` ![](https://i.imgur.com/k2leBRy.png) ### Difference #### `(a - b)` ![](https://i.imgur.com/soh0G8N.png) #### `(b - a)` ![](https://i.imgur.com/UhNIrjj.png) ```python= # declaring sets a = {1, 2, 3} b = {3, 4, 5} print(a) # => {1, 2, 3} print(b) # => {3, 4, 5} # methods: union, intersection, symmetric_difference, difference print(a | b) # => {1, 2, 3, 4, 5} print(a & b) # => {3} print(a - b) # => {1, 2} print(b - a) # => {4, 5} print(a ^ b) # => {1, 2, 4, 5} # print(a + b) # => error # alternate syntax print(a.union(b)) print(a.intersection(b)) print(a.symmetric_difference(b)) print(a.difference(b)) print(b.difference(a)) # with multiple operators, evaluation will happen from left to right! c = {5, 6, 7} print(a & b | c) # => {3, 5, 6, 7} # you can make sets out of lists, strings, tuples lst = [1,2,3,4,5,5] print(set(lst)) # => {1, 2, 3, 4, 5} string = "hello" print(set(string)) # => {'l', 'h', 'o', 'e'} print(set((1,1,1))) # => {1} # and vice versa with lists and tuples print(list(a)) # => [1, 2, 3] # Some examples of times when sets are useful # identifying overlapping values across different groups # comments on posts # traversing cyclical graphs ``` # Example Stacks and Queues using Lists ```python= # Stacks and Queues # stacks # first in, last out # when would use a stack? # dispensing pez # packing and unpacking # iteratively doing depth first search # interuption stack example teller = [] teller.append("Greet customer") print(teller) teller.pop() print(teller) teller.append("Process Deposit") print(teller) teller.append("Phone Ringing") print(teller) teller.pop() teller.append("Greet Caller, Listen, Answer Question") print(teller) teller.pop() print(teller) teller.pop() print(teller) # queues # first in first out # when would i use a queue? # breadth first tree search # processing of client orders ## processing queue processor = [] processor.append({'type':'page','path':'','header':[],'cookies':[]}), processor.append({'type':'api', 'function':'', 'parameters':[]}) processor.append({'email':'email','address':'bob@gmail.com','subject':''}) print("PROCESSOR LIST", processor) for i in range(len(processor)): item = processor.pop(0) print("PROCESSING ITEM", item) print("REMAINING LIST", processor) ``` # Built-in Functions ```python= # Built-in functions # all() checks that there are no falsey items test1 = {"item", "truthy", ""} test2 = [] test3 = [[]] print(all(test1), test1) # => False {'', 'truthy', 'item'} print(all(test2), test2) # => True [] print(all(test3), test3) # => False [[]] # any() checks that there is at least one truthy item test1 = ["item", [], []] test2 = [] test3 = [[]] print(any(test1), test1) # => True ['item', [], []] print(any(test2), test2) # => False [] print(any(test3), test3) # => False [[]] # filter scores = [90, 86, 75, 91, 62, 99, 88, 90] print(scores) def isA(num): if num >= 90: return num else: return False aScores = filter(isA, scores) # aScores = filter(lambda num: num >= 90, scores) # this would also work print(aScores) print(list(aScores)) print(scores) def getGrade(num): if (num >= 90): return "A" elif (num <90 and num >= 80): return "B" elif (num < 80 and num >= 70): return "C" elif (num < 70 and num >= 60): return "D" else: return "F" grades = list(map(getGrade, scores)) print(grades) # print("ZIPPED GRADES AND SCORES") combined = zip(scores, grades) combined_list = list(zip(scores, grades)) print(combined) print(combined_list) # getting unique usernames comments = [ ("Marni", "hi this is fun"), ("bob", "no its not"), ("Marni", "okay, u r right bob thx"), ] def get_username(comment): return comment[0] usernames = list(map(get_username, comments)) print(usernames) unique_commenters = set(usernames) # custom sorting def sorter(comment): return comment[0].lower() print(comments) comments.sort(key=sorter, reverse=True) print(comments) ```