<a target="_blank" href="https://drive.google.com/file/d/1ryNRT-_TB12NMuxOK7gKEhgp9ICGrR_s/view?usp=sharing"><img src="https://www.tensorflow.org/images/colab_logo_32px.png" />Run in Google Colab</a> <br /> # Intro to Python - Part II In this notebook, we focus on **string**, **list**, and **dictionary** in Python. ## Strings A string is a sequence of characters. You can access the characters one at a time with the bracket operator: ```python fruit = 'banana' letter_b = fruit[0] letter_b ``` 'b' The expression in brackets is called an **index**. The index indicates which character in the sequence you want. _Notice that the first letter has the index 0_. **len()** is a built-in function that returns the number of characters in a string. ```python len(fruit) ``` 6 ### Traversal with loops A lot of computations involve processing a string one character at a time. Often they start at the beginning, select each character in turn, do something to it, and continue until the end. This pattern of processing is called a traversal. **Exercise**: _Write a function that takes a string as an argument and displays the letters backward._ ```python def reverse_str(s): index = len(s) - 1 while index > -1: print(s[index], end='') index = index - 1 reverse_str('Hello Python') ``` nohtyP olleH Another way to write a traversal is with a `for` loop: ```python for char in fruit: print(char) ``` b a n a n a Each time through the loop, the next character in the string is assigned to the variable char. The loop continues until no characters are left. ### String slices A segment of a string is called a **slice**. Selecting a slice is similar to selecting a character: ```python fruit[1:4] ``` 'ana' ```python fruit[2:5] ``` 'nan' The operator `[n:m]` returns the part of the string from the “n-eth” character to the “m-eth” character, including the first but excluding the last. This behavior is counterintuitive, but it might help to imagine the indices pointing between the characters <img src="https://i.imgur.com/uZUDVyB.png" width="200ps" /> If you omit the first index (before the colon), the slice starts at the beginning of the string. If you omit the second index, the slice goes to the end of the string. ```python fruit[:3] ``` 'ban' ```python fruit[2:] ``` 'nana' **Quiz**: _Given that `s` is a string, what does `s[:]` mean?_ ### String methods A **method** is similar to a function—it takes arguments and returns a value—but the syntax is different. ```python name = "CoderSchool" new_name = name.upper() print('name:', name) print('new_name:', new_name) ``` name: CoderSchool new_name: CODERSCHOOL This form of dot notation specifies the name of the method, `upper`, and the name of the string to apply the method to, `name`. A method call is called an **invocation**; in this case, we would say that we are invoking `upper` on the `name`. Here below are some useful string methods: ```python # all lowercase name.lower() ``` 'coderschool' ```python # check if the string starts with a specified value name.startswith('Coder') ``` True ```python # check if the string ends with a specified value name.endswith('school') ``` False ```python # str.split() method returns a list of strings that are separated by whitespace by default quote = "To be or not to be" words = quote.split() words ``` ['To', 'be', 'or', 'not', 'to', 'be'] ```python # str.split() can remove certain parts of an original string date = '2020-20-02' date.split('-') ``` ['2020', '20', '02'] ```python # str.join() - sewing a list of strings up into one long string, using the string it was called on as a separator. '-'.join(words) ``` 'To-be-or-not-to-be' ```python numbers = ['100', '000', '000'] '.'.join(numbers) ``` '100.000.000' ## Lists Like a string, a **list** is a sequence of values. In a string, the values are characters; in a list, they can be any type. The values in a list are called **elements** or sometimes **items**. ```python nums = [1, 2, 3, 4] maths = ['statistics', 'calculus', 'linear algebra'] empty_list = [] print(len(nums)) print(len(maths)) print(len(empty_list)) ``` 4 3 0 A list that contains no elements is called an empty list; you can create one with empty brackets, `[]`. A list within another list is **nested**: ```python matrix = [ [1, 2, 3], [4, 5, 6] ] ``` The syntax for accessing the elements of a list is the same as for accessing the characters of a string—the bracket operator. The expression inside the brackets specifies the index. Remember that the indices start at 0: ```python print(nums[0]) print(maths[1]) print(matrix[0][2]) ``` 1 calculus 3 The **slice operator [n:m]** also works on lists: ```python letters = ['a', 'b', 'c', 'd', 'e', 'f'] print(letters[1:3]) print(letters[:3]) print(letters[3:]) print(letters[::-1]) ``` ['b', 'c'] ['a', 'b', 'c'] ['d', 'e', 'f'] ['f', 'e', 'd', 'c', 'b', 'a'] ### List methods **append()** adds a new element to the end of a list: ```python letters.append('g') letters ``` ['a', 'b', 'c', 'd', 'e', 'f', 'g'] **extend()** takes a list as argument and appends all of the elements: ```python letters.extend(['h', 'i', 'j']) letters ``` ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'] **pop()** modifies the list and returns the element that was removed. If you don’t provide an index, it deletes and returns the last element. ```python last_letter = letters.pop() print(last_letter) print(letters) ``` j ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i'] ```python second_letter = letters.pop(1) print(second_letter) print(letters) ``` b ['a', 'c', 'd', 'e', 'f', 'g', 'h', 'i'] If you don’t need the removed value, you can use the **del** operator: ```python del letters[0] print(letters) ``` ['c', 'd', 'e', 'f', 'g', 'h', 'i'] ## Dictionaries Dictionaries are a built-in Python data structure for mapping **keys** to **values**. To define a Dictionary, we use curly braces `{}` ```python numbers = {'one':1, 'two':2, 'three':3} ``` In this case `'one'`, `'two'`, and `'three'` are the **keys**, and 1, 2 and 3 are their corresponding **values**. Values are accessed via square bracket syntax `[]` similar to indexing into lists and strings. ```python numbers['one'] ``` 1 We can use the same syntax to add another `key-value` pair: ```python numbers['eleven'] = 11 print(numbers) ``` {'one': 1, 'two': 2, 'three': 3, 'eleven': 11} Or to change the value associated with an existing key: ```python numbers['one'] = 'eins' print(numbers) ``` {'one': 'eins', 'two': 2, 'three': 3, 'eleven': 11} A for loop over a dictionary will loop over its keys: ```python for k in numbers: print(k, '=', numbers[k]) ``` one = eins two = 2 three = 3 eleven = 11 ### Dictionaries methods We can access a collection of all the keys or all the values with **`dict.keys()`** and **`dict.values()`**, respectively. ```python print(numbers.keys()) print(numbers.values()) ``` dict_keys(['one', 'two', 'three', 'eleven']) dict_values(['eins', 2, 3, 11]) The very useful **`dict.items()`** method lets us iterate over the keys and values of a dictionary simultaneously. ```python numbers.items() ``` dict_items([('one', 'eins'), ('two', 2), ('three', 3), ('eleven', 11)]) ```python for key, value in numbers.items(): print(key, value) ``` one eins two 2 three 3 eleven 11 ### Example Write a function called `letters_histogram()` that takes a string as an argument and return a dictionary that shows how many times each letter appears. For example `letters_histogram('aabbc')` should return `{'a': 2, 'b': 2, 'c': 1}` ```python def letters_histogram(s): d = {} for letter in s: if letter not in d: d[letter] = 1 else: d[letter] = d[letter] + 1 return d ``` ```python letters_histogram('aabbc') ``` {'a': 2, 'b': 2, 'c': 1} ## List and Dictionary comprehension **List comprehensions** are one of Python's most beloved and unique features. - It provides a concise way to create lists. - It consists of squarre brackets containing an expression followed by a `for` clause, then zero or more `for` or `if` clauses. The expressions can be anything, meaning you can put in all kinds of objects in lists. - The result will be a new list resulting from evaluating the expression in the context of the `for` and `if` clauses which follow it. The list comprehension starts with a `[` and `]`, to help you remember that the result is going to be a list. The basic syntax is: ```python [ expression for item in list if conditional ] ``` ```python even_numbers = [x for x in range(5) if x % 2 == 0] # [0, 2, 4] squares = [x * x for x in range(5)] # [0, 1, 4, 9, 16] even_squares = [x * x for x in even_numbers] # [0, 4, 16] ``` **Dictionary comprehension** is equivalent: ```python square_dict = {x: x * x for x in range(5)} # {0: 0, 1: 1, 2: 4, 3: 9, 4: 16} square_set = {x * x for x in [1, -1]} # {1} ``` A list comprehension can include multiple `for`: ```python pairs = [(x, y) for x in range(10) for y in range(10)] # 100 pairs (0,0) (0,1) ... (9,8), (9,9) ``` Another cool thing is the **interpretation** ```python new_list = [expression(i) for i in old_list if filter(i)] ``` - **new_list**: The new list (result). - **expression(i)**: Expression is based on the variable used for each element in the old list. - **for i in old_list**: The word for followed by the variable name to use, followed by the word in the old list. - **if filter(i)**: Apply a filter with an If-statement. The easiest way to understand them is probably to just look at a few examples: ```python job_titles = ['CEO', 'CTO', 'COO', 'Developer', 'Product Manager'] # Write a function that takes in a list of job titles and return list of titles with length less than 4 def short_titles(lst): result = [] for title in lst: if len(title) < 4: result.append(title) return result short_titles(job_titles) ``` ['CEO', 'CTO', 'COO'] Here is a solution using list comprehension: ```python def short_titles_2(lst): return [title for title in lst if len(title) < 4] ``` ```python short_titles_2(job_titles) ``` ['CEO', 'CTO', 'COO'] Much better, right? ## Exercises ### Exercise 1 Write a function that takes a string as an argument, and count how many `a` letter appears in the string. ```python def count_letter_a(s): # YOUR_CODE HERE ``` ### Exercise 2 A palindrome is a word that is spelled the same backward and forward, like “noon” and “redivider”. Recursively, a word is a palindrome if the first and last letters are the same and the middle is a palindrome. Write a function called `is_palindrome` that takes a string argument and returns `True` if it is a palindrome and `False` otherwise. **Hint**: _A string slice can take a third index that specifies the "step size;" that is, the number of spaces between successive characters. A step size of 2 means every other character; 3 means every third, etc._ ``` fruit = 'banana' fruit[0:5:2] 'bnn' ``` _A step size of -1 goes through the word backwards, so the slice `[::-1]` generates a reversed string._ ```python def is_palindrome(s): # YOUR_CODE HERE ``` ### Exercise 3 Write a function called middle that takes a list and returns a new list that contains all but the first and last elements. So `middle([1,2,3,4])` should return `[2,3]`. ```python def middle(lst): # YOUR_CODE HERE ``` ### Exercise 4 Write a function that takes a list of numbers and returns the cumulative sum; that is, a new list where the ith element is the sum of the first i+1 elements from the original list. For example, the cumulative sum of `[1, 2, 3]` is `[1, 3, 6]`. ```python def cumulative_sum(lst): # YOUR_CODE HERE ``` ### Exercise 5 Run this cell below to define the data: ```python shoppingCart = [ { 'id': 'A31', 'item': 'T-shirt', 'price': 9.9, 'quantity': 5 }, { 'id': 'A32', 'item': 'Jacket', 'price': 99.9, 'quantity': 1 }, { 'id': 'A33', 'item': 'Skirt', 'price': 19.9, 'quantity': 2 }, { 'id': 'A34', 'item': 'Ankle Pant', 'price': 39.9, 'quantity': 3 }, { 'id': 'A35', 'item': 'Polo shirt', 'price': 14.9, 'quantity': 3 }, { 'id': 'A36', 'item': 'Chino Short', 'price': 29.9, 'quantity': 2 }, { 'id': 'A37', 'item': 'Easy Short', 'price': 19.9, 'quantity': 2 }, ] ``` - Write a function that returns an array of prices for each product in the cart (item price \* quantity). - Write a function that returns the total price. ```python def product_prices(cart): # YOUR_CODE_HERE def total_price(cart): # YOUR_CODE_HERE ``` ## References - [CheckIO](http://www.checkio.org/): a gamified website containing programming tasks in Python 3 - [LearnPython](https://www.learnpython.org/): an interactive Python tutorial that is suitable for absolute beginners - [Automate the Boring Stuff with Python](https://automatetheboringstuff.com/): small and practical programs to automate tasks on the computer - [Think Python](https://greenteapress.com/thinkpython/html/index.html): how to think like a computer scientist