<style> .present { text-align: left; } img[alt=set_operations] { width: 60%; } </style> # Python Collections and Built-ins ## Week 17 Day 3 --- ## Videos 1 (14 minutes) Watch: - Lists in Python (10:15) --- ### Lists Lists are mutable, ordered collections (like arrays in JavaScript). Use square brackets to make lists. ```python= empty = [] print(empty) # [] ``` Values are separated by commas. ```python= fruits = ["banana", "apple", "kiwi"] print(fruits) # ["banana", "apple", "kiwi"] ``` --- ### Indexing with lists To get individual values: - `list_name[single_index]` ```python= fruits = ["banana", "apple", "kiwi", "mango", "tangerine"] print(fruits[1]) # apple print(fruits[-1]) # tangerine ``` --- ### Indexing with lists (ranges) To get a range of values: ```python= fruits = ["banana", "apple", "kiwi", "mango", "tangerine"] # list_name[inclusive_start:exclusive_end] print(fruits[1:4]) # ["apple", "kiwi", "mango"] print(fruits[-1:]) # ["tangerine"] # list_name[inclusive_start:exclusive_end:step_size] print(fruits[::-1]) # ["tangerine', "mango', "kiwi", "apple", "banana"] print(fruits[3::-1]) # ["mango", "kiwi", "apple", "banana"] ``` --- ### Built-in functions (`len()`) We can use the `len()` function to get the length of lists. ```python= fruits = ["banana", "apple", "kiwi", "mango", "tangerine"] print(len(fruits)) # 5 print(len(fruits[1:4])) # 3 ``` --- ## Practices 1 (20 min) - Explore The List (5:00) - Return First Element Of A List (2:00) - First And Last Entries (1:00) - Check Nested Arrays (10:00) --- ## Lecture Videos 2 (7 minutes) Watch: - Doing Math With Lists (5:07) Discuss code only: - Mutability Of and Sorting Lists (12:51) --- ### List methods Use `append` to add items to the end of a list (like `push` in JavaScript). This mutates the list. ```python= fruits = ["banana", "apple", "kiwi"] fruits.append("apple") print(fruits) # ["banana", "apple", "kiwi", "apple"] ``` Use `remove` to delete the first instance of a given value. (Also mutates the list). ```python= fruits.remove("apple") print(fruits) # ["banana", "kiwi", "apple"] # Error if value is not present in list fruits.remove("mango") # ValueError: list.remove(x): x not in list ``` (for more list methods, check out [the documentation here](https://docs.python.org/3/tutorial/datastructures.html).) --- ### Sorting lists The `.sort()` method will sort a list, mutating the list ```python= fruits = ["mango", "banana", "apple", "kiwi"] fruits.sort() print(fruits) # ["apple", "banana", "kiwi", "mango"] ``` --- ### Sorting lists (custom sort) You can provide a key to change how the list is sorted - the key is a function - rather than sort the list values directly, the sort will apply the key function to each value and sort based on the resulting value - this will not mutate the values in the list (just the order), it will just use the calculated values in the comparisons ```python= names = ["janie", "Julie", "Allie", "pamela"] names.sort() print(names) # ["Allie", "Julie", "janie", "pamela"] # ensure a case-insensitive sort with the `.lower` string method names.sort(key=str.lower) print(names) # ["Allie", "janie", "Julie", "pamela"] ``` --- ### Sorting, continued The `sorted()` function can be used to sort lists without mutating. It also works with other iterable types (e.g. tuples). ```python= fruits = ["mango", "banana", "apple", "kiwi"] sorted_fruits = sorted(fruits) reversed_fruits = sorted(fruits, reverse=True) print(sorted_fruits) # ['apple', 'banana', 'kiwi', 'mango'] print(reversed_fruits) # ['mango', 'kiwi', 'banana', 'apple'] ``` - note that the parameters `key` and `reverse` work with both `.sort()` and `sorted()` --- ### Sorting lists (fun fact) Sorting in Python uses [Timsort](https://en.wikipedia.org/wiki/Timsort). (The inventor's name is Tim. Really.) It is based on a combination of merge sort and insertion sort, and it is designed to perform optimally on real data. --- ### More built-in functions `sum()`, `min()`, `max()`, can be used to compute values over lists. ```python= values = [49, 22, 13, 25] print(values) # [49, 22, 13, 25] total_value = sum(values) print(total_value) # 109 top_value = max(values) print(top_value) # 49 min_value = min(values) print(min_value) # 13 avg_val = sum(values)/len(values) print(avg_val) # 27.25 ``` --- ## Practices 2 (15 min) - Find The Smallest Number In A List (5:00) - Sum The Elements Of A List (5:00) - Maximum Difference (5:00) --- ## Lecture Videos 3 (22 minutes) Watch: - Tuples in Python (17:07) - Special Case: Single Item Tuple (2:46) --- ### Tuples - Tuples are an ordered, immutable collection type. - They are defined using parentheses `()`, with values separated by a comma. ```python= a = (1, 2, 3, 4, 5, 6, 7, 8, 9) b = ('a', 'b', 'c', 'd', 'e') c = 10, 20, 30 print(a) # (1, 2, 3, 4, 5, 6, 7, 8, 9) print(b) # ('a', 'b', 'c', 'd', 'e') print(c) # (10, 20, 30) ``` --- ### Tuples are immutable [1/2] - You cannot append, remove, or sort the tuple in place. - However, they are not constants. ```python= tup = ("tall", "wide") tup = ("small", "narrow") # no error, this works print(tup) # ("small", "narrow") tup += ("tall", "wide") # no error, this works print(tup) # ("small", "narrow", "tall", "wide") ``` --- ### Tuples are immutable [2/2] Mutable items in a tuple can be mutated: ```python= tup = ([1, 2, 3], "hello") print(tup[0]) # [1, 2, 3] tup[0].append(4) print(tup[0]) # [1, 2, 3, 4] print(tup) # ([1, 2, 3, 4], "hello") ``` --- ### Sorting The `sorted()` function works on tuples, just like lists. This will return a list by default. ```python= fruits = ("banana", "apple", "kiwi") print(sorted(fruits)) # ['apple', 'banana', 'kiwi'] sorted_fruits = tuple(sorted(fruits)) print(sorted_fruits) print(fruits) ``` --- ### Returning tuples - Using a comma in your return statement will return a tuple - You can store the tuple in one variable or destructure the tuples values into multiple variables. ```python= def min_max(numbers): return min(numbers), max(numbers) values = (14, 2, -2, 3.3, -8, -25, 9, 0) low_and_high = min_max(values) print(low_and_high) # (-25, 14) lowest, highest = min_max(values) print(lowest) # -25 print(highest) # 14 ``` --- ### Singleton tuples Since parentheses are also used for grouping, python won't interpret a single like you might expect. ```python= hopefully_a_tuple = (5) print(hopefully_a_tuple) # 5 # whoops! not a tuple ``` You need to use a comma so that python can recognize that a tuple is present. ```python= hopefully_a_tuple = (5,) print(hopefully_a_tuple) # (5,) # nice, that is a tuple also_a_tuple= 5, print(also_a_tuple) # (5,) # awesome, that is also a tuple ``` --- ## Practices 3 (5 min) - Explore The Tuple (5:00) --- ## Lecture Videos 4 (10 minutes) Watch: - Ranges in Python (9:00) --- ### Ranges - An immutable list of numbers in order - Arguments: - start (default 0) - stop (required) - step (default 1) - Can go in forward or reverse order - Range is exclusive(the stop argument is not included in the returned list) --- ### Declaring Basic Ranges ```python= numbers_range = range(10) print(numbers_range) # range(0, 10) print(list(numbers_range)) # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] starting_at_one = range(1, 11) print(list(starting_at_one)) # [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] ``` --- ### Reverse Ranges ```python= reversed_maybe = range(51, 5) print(list(reversed_maybe)) # [] reversed = range(51, 5, -1) print(list(reversed)) # [51, 50, ... 9, 8, 7, 6] ``` --- ### Iterating over Collections and Using Ranges ```python= items = ['a', 'b', 'c'] for item in items: print(item) for i in range(len(items)): print(i, items[i]) for i in range(1, 10, 2): print(i) ``` --- ## Practices 4 (7 min) - Explore The Range (5:00) - Range Loops (2:00) --- ## Lecture Videos 5 (10 minutes) Watch: - Dictionaries in Python (8:31) Discuss Code Only: - More Ways To Make A Dictionary (10:08) --- ### Dictionaries - Dictionaries are ordered and mutable. - They consist of pairs of keys and values. - The keys must be "hashable" (immutable) values - e.g. keys can be strings, numbers, tuples, booleans, but not lists or dictionaries - Dictionaries use curly braces, similar to JavaScript objects, although keys do not have to be strings. - but if the keys _are_ strings, they must use quotes, unlike JS --- ### Declaring Dictionaries ```python= a = {'one':1, 'two':2, 'three':3} b = dict(one=1, two=2, three=3) c = dict([('two', 2), ('one', 1), ('three', 3)]) print(a == b == c) # True ``` If keys and values are the same, they are considered equivalent, doesn't matter how they were defined --- ### Using `[]` and `.get()` to index into a Dictionary - Unlike javascript in Python you cannot index into a dictionary with dot notation ```python= my_dict = {'one':1, 'two':2, 'three':3} print(my_dict.one) #AttributeError: 'dict' object has no attribute 'one' print(my_dict['one']) #1 print(my_dict['new']) # KeyError: 'new' print(my_dict.get('one', None)) # 1 print(my_dict.get('gorilla', None)) # None ``` --- ### Adding, Updating, Deleting Data in Dictionaries - `del` keyword to delete a key/value pair - `[]` to add or update a key/value pair ```python= my_dict = { "word": "cooool", 1: "one", False: 42, ("tuple", "keys"): ["lists", "can", "be", "values", "not", "keys"], None: {"key": "value"} } my_dict[1] = "two" # Updates value print(my_dict[1]) # "two" my_dict["new_key"] = "new_value" #Adds key/value del my_dict["word"] # Deletes key/value print(my_dict) # I promise, all the changes are there! ``` --- ### Using `in` - `in` allows you to check if a value is a key in the dictionary ```python= print(1 in {1: "one", 2: "two"}) # True print("1" in {1: "one", 2: "two"}) # False print(4 in {1: "one", 2: "two"}) # False print("one" in {1: "one", 2: "two"})# False ``` --- ### .items() - `.items()` returns a list of tuples - Each tuple contains the key/value pair of the item in the dictionary ```python= book = { 'title': 'Goodnight Moon', 'ratings': 7492, 'stars': 4.8, 'author': {'firstName': 'Margaret', 'lastName': 'Wise Brown'}, 'images': ['goodnight1.png', 'goodnight2.png'], } for key, value in book.items(): print('key:', key, 'value:', value) for key in book: print('key:', key, 'value:', book[key]) ``` --- ### `.keys()` and `.values()` - `.keys()` returns a list of the keys in the dictionary - `.values()` returns a list of the values in the dictionary ```python= book = { 'title': 'Goodnight Moon', 'ratings': 7492, 'stars': 4.8, 'author': {'firstName': 'Margaret', 'lastName': 'Wise Brown'}, 'images': ['goodnight1.png', 'goodnight2.png'], } for value in book.values(): print('value:', value) for key in book.keys(): print('key:', key) ``` --- ## Practices 5 (15 minutes) - Explore The Dictionary (5:00) - Does The Dictionary Have A Key? (2:00) - Is The Dictionary Empty? (1:00) - Create Name Tag (5:00) --- ## Lecture Videos 6 (18 minutes) Watch: - Sets in Python (12:19) - Using Sets (2:42) Discuss code only: - Combining Data Structures (7:32) - Stack And Queue Overview (13:26) --- ### Sets Sets are mutable, unordered collections where all elements are unique. Sets use curly braces, like a dictionary. You can create an empty set with `set()`. While sets can be mutated, the individual elements must be immutable types. ```python= not_an_empty_set = {} print(type(not_an_empty_set)) # <class 'dict'> empty_set = set() print(type(empty_set)) # <class 'set'> set_with_elements = {1, "hello", None} print(set_with_elements) # {1, None, "hello"} no_duplicates = {1, 1, 1} print(no_duplicates) # {1} ``` --- ### Set operations #### Union `(a | b)` ![set_operations](https://i.imgur.com/5bY2S1u.png) ```python= a = {1, 2, 3} b = {3, 4, 5} print(a | b) # {1, 2, 3, 4, 5} print(a.union(b)) # {1, 2, 3, 4, 5} # order of a and b does not matter ``` --- ### Set operations #### Intersection `(a & b)` ![set_operations](https://i.imgur.com/dyvvZAv.png) ```python= a = {1, 2, 3} b = {3, 4, 5} print(a & b) # {3} print(a.intersection(b)) # {3} # order of a and b does not matter ``` --- ### Set operations #### Symmetric difference `(a ^ b)` ![set_operations](https://i.imgur.com/k2leBRy.png) ```python= a = {1, 2, 3} b = {3, 4, 5} print(a ^ b) # {1, 2, 4, 5} print(a.symmetric_difference(b)) # {1, 2, 4, 5} # order of a and b does not matter ``` --- ### Set operations #### Difference `(a - b)` ![set_operations](https://i.imgur.com/soh0G8N.png) ```python= a = {1, 2, 3} b = {3, 4, 5} print(a - b) # {1, 2} print(a.difference(b)) # {1, 2} ``` --- ### Set operations #### Difference `(b - a)` ![set_operations](https://i.imgur.com/UhNIrjj.png) ```python= a = {1, 2, 3} b = {3, 4, 5} print(b - a) # {4, 5} print(b.difference(a)) # {4, 5} ``` --- ### Sets operations, continued With multiple operators, evaluation will happen from left to right. ```python= a = {1, 2, 3} b = {3, 4, 5} c = {5, 6, 7} print(a & b | c) # {3, 5, 6, 7} print((a & b) | c) # {3, 5, 6, 7} print(a & (b | c)) # {3} ``` --- ### Creating sets from other iterables You can use the `set()` function to create new sets from other iterable types. ```python= my_list = [1, 2, 3, 4, 5, 5] print(set(my_list)) # {1, 2, 3, 4, 5} my_string = "hello" print(set(my_string)) # {'l', 'h', 'o', 'e'} my_tuple = (1, 1, 1) print(set(my_tuple)) # {1} my_dict = {"hello": "value", "goodbye": "value"} print(set(my_dict)) # {'goodbye', 'hello'} ``` --- ### Code from "Combining Data Structures" ```python= # posts is a list of dictionaries, some of the values in that list posts = [ { "title": "All About Lists", "tags": ("fun", "informative", "lists") }, { "title": "Tuple Trouble", "tags": ("fun", "tuples") }, { "title": "Sparkling Sets", "tags": ("informative", "numbers") }, ] all_tags = [] # list to hold all tags for i in range(len(posts)): print(posts[i]["tags"]) all_tags.extend(posts[i]["tags"]) print(all_tags) print(set(all_tags)) all_tags = list(set(all_tags)) all_tags.sort() print(all_tags) ``` --- ### Code example from "Stack and Queue Overview" #### Interuption stack ```python= 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) ``` --- ### Code example from "Stack and Queue Overview" #### Processing queue ```python= 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) ``` --- ## Lecture Videos 7 (30 minutes) Watch: - Built-Ins: All And Any (8:00) - Built-Ins: Filter and Map (10:32) - Built-Ins: Custom Sort (9:05) Discuss code only: - Local Packages And Modules --- ### Built-in functions (`all()`) The `all()` function checks that there are _no_ falsey items in the provided collection. ```python= test1 = {"item", "truthy", ""} test2 = [] test3 = [[]] print(all(test1), test1) print(all(test2), test2) print(all(test3), test3) ``` --- ### Built-in functions (`all()`) Answers: ```python= test1 = {"item", "truthy", ""} test2 = [] test3 = [[]] print(all(test1), test1) # False {"", "truthy", "item"} print(all(test2), test2) # True [] print(all(test3), test3) # False [[]] ``` --- ### Built-in functions (`any()`) The `any()` checks that there is at least one truthy item in the provided collection ```python= test1 = ["item", [], []] test2 = [] test3 = [[]] print(any(test1), test1) print(any(test2), test2) print(any(test3), test3) ``` --- ### Built-in functions (`any()`) Answers: ```python= test1 = ["item", [], []] test2 = [] test3 = [[]] print(any(test1), test1) # True ['item', [], []] print(any(test2), test2) # False [] print(any(test3), test3) # False [[]] ``` --- ### Built-ins (`filter()`) The `filter()` function takes a function and an iterable, and it returns a "filter object". The returned collection includes only the items which, when the function parameter was applied to them, returned a truthy value. ```python= def is_a(num): if num >= 90: return True else: return False scores = [90, 86, 75, 91, 62, 99, 88, 90] only_as = filter(is_a, scores) # does not mutate original print(only_as) # <filter object at 0x10546ad30> print(list(only_as)) # [90, 91, 99, 90] ``` --- ### Built-ins (`filter()`) `filter`'s function parameter can also be defined in line as a `lambda` function. ```python= scores = [90, 86, 75, 91, 62, 99, 88, 90] only_as = filter(lambda num: num >= 90, scores) print(only_as) # <filter object at 0x10546ad30> print(list(only_as)) # [90, 91, 99, 90] ``` --- ### Built-ins (`map()`) The `map()` function takes a function and an iterable, and it returns a "map object" that transforms each value from the original iterable, according to the provided function. ```python= def get_grade(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" scores = [90, 86, 75, 91, 62, 99, 88, 90] print(map(get_grade, scores)) # <map object at 0x106faffa0> grades = list(map(get_grade, scores)) print(grades) # ['A', 'B', 'C', 'A', 'D', 'A', 'B', 'A'] ``` --- ### Built-ins (`zip()`) The `zip()` function takes two iterables and returns a "zip object" that pairs values at corresponding indices. You can convert the "zip object" into a list of tuples with the `list()` function. ```python= scores = [90, 86, 75, 91, 62, 99, 88, 90] grades = ["A", "B", "C", "A", "D", "A", "B", "A"] combined = zip(scores, grades) combined_list = list(combined) combined_dict = dict(combined_list) print(combined) # <zip object at 0x1023a9600> print(combined_list) # [(90, 'A'), (86, 'B'), (75, 'C'), (91, 'A'), (62, 'D'), (99, 'A'), (88, 'B'), (90, 'A')] print(combined_dict) # {90: 'A', 86: 'B', 75: 'C', 91: 'A', 62: 'D', 99: 'A', 88: 'B'} ``` --- ### Basic imports in Python Basic imports in Python are backwards from JavaScript. ```python= # from module_name import variable_name from random import randint print(randint(0, 10)) ``` You can also import an entire module, and then access all the values from it using dot notation. ```python= import random print(random.randint(0, 10)) ``` --- ### ~~Exports in Python~~ Unlike JavaScript, Python does not require exports. All of the objects, classes, functions, etc. that are defined in a module are automatically available to import. --- ## Practices 7 (5 min) - All Occurrences Of A Value In A List (5:00) --- ## Summary Practices (60 minutes) - Guess A Number Game - Bonus: Track The Robot - Bonus: Averages ## Summary Quizzes (5 minutes) - Structured Data Quiz (5:00)