***** Lists ***** * We saw that strings were a little different when compared to the other types we've seen (``int``, ``float``, ``bool``) * We can generalize the idea of strings to more types * A string is a collection of characters * We can use lists to have a collection of other types .. admonition:: Activity :class: activity Run the following code: .. code-block:: python :linenos: some_list = [5, 7, 9, 10] print(some_list) print(some_list[0]) print(some_list[1:3]) print(type(some_list)) #. Determine what types can be in a list. #. Can a list contain things of different types at the same time? #. How can you access the last element in a list? #. Can we find the length of a list? #. Is it possible to have a list of length 0? This would be an empty list, or a list with nothing in it. Data Structures =============== * The ``list`` is your first real **data structure** * As the name suggests, a data structure is some *structure* that holds *data* * Lists, although simple, are exceptionally useful and important .. raw:: html .. admonition:: Activity :class: activity Apply what you know about loops, strings, and lists to solve the following problems --- combining algorithms and data structures is a big part of programming. **Hint:** You will probably find the linear searches from the strings topic to be helpful. #. Write a function ``contains_while(needle, haystack) -> bool:`` that uses a ``while`` loop and returns ``True`` if needle is contained in the haystack and ``False`` otherwise. #. Write a function ``index_of_for(needle, haystack) -> int:`` that uses a ``for`` loop and returns the index of needle within the haystack or ``-1`` if it is not found. #. Write some ``assert`` tests for both functions to verify correctness. List Operators and Methods ========================== * Similar to strings, we can concatenate lists with the ``+`` operator .. code-block:: python :linenos: some_list = [5, 6, 7, 8, 9] some_other_list = ["this", "is", "a", "list"] bigger_list = some_list + some_other_list print(bigger_list) # Results in [5, 6, 7, 8, 9, 'this', 'is', 'a', 'list'] * We can concatenate a list with itself multiple times using the ``*`` operator .. code-block:: python :linenos: some_list = [5, 6, 7, 8, 9] triple_list = some_list * 3 print(triple_list) # Results in [5, 6, 7, 8, 9, 5, 6, 7, 8, 9, 5, 6, 7, 8, 9] .. admonition:: Activity :class: activity #. Create some list and assign it to a variable ``some_list`` #. ``print`` out the list --- ``print(some_list)`` #. After running the code, type ``some_list.`` and wait * Don't forget the dot ``.`` #. Play around with some of the methods you see Mutability ========== * Although lists and strings have some things in common, one thing they do not have in common is *mutability* * Remember, strings are *immutable* * We can index strings and lists the same way to access individual elements * But unlike strings, we can also change the elements at a specific index .. code-block:: python :linenos: another_list = ["a", "b", "c", "d", "e"] another_list[2] = "X" print(another_list) # Results in ['a', 'b', 'X', 'd', 'e'] Lists & Loops ============= * Similar to how ``for`` loops made it easy to iterate over each character in a string * ``for`` loops can be used the same way on lists to iterate over each element in the list * ``for`` each *thing* in a collection of *things* .. code-block:: python :linenos: collection_of_things = ["Hello", 10, True, 100.001] for thing in collection_of_things: print(thing) # Results in # Hello # 10 # True # 100.001 * Iterating over a *collection of things* is very common * Expect to start using ``for`` loops like this a lot * In fact, this was used in assignment 1 multiple times * Iterating over the contents of the file being read * Iterating over the list of ``(latitude, longitude)`` pairs Range ----- * ``range`` is a very handy function that we often use with ``for`` loops * It provides an easy way to loop over a specific range of numbers .. code-block:: python :linenos: for i in range(5): print(i) # Results in # 0 # 1 # 2 # 3 # 4 * Notice that the integer ``5`` was specified in the ``range`` function, and the loop ran a total of ``5`` times * But because of ``0`` based indexing, the the number ``5`` is not actually included * A big reason we like to use ``for`` loops this way is because the syntax is so simple and clean * The above functionality can be achieved with a ``while`` loop, but the code needed is a little more cumbersome .. code-block:: python :linenos: i = 0 while i < 5: print(i) i += 1 # Results in # 0 # 1 # 2 # 3 # 4 .. admonition:: Activity :class: activity Write a function ``beer_on_wall`` that prints out ``"n bottles of beer on the wall"`` for all ``n`` from ``99`` down to ``0``. This function must use a ``for`` loop with the ``range`` function. The difficulty here is the need to count backwards. `Perhaps a read of the documentation can help. `_ .. raw:: html Looping Over Indices and Enumerate ---------------------------------- * Sometimes it is important to know the indices of each element being printed out * For example, if the goal is to do a linear search to find the index of a given element, the following would be problematic .. code-block:: python :linenos: def index_of_uhoh(needle, haystack): for element in haystack: if element == needle: return "????" # How do I find the index? return -1 * Using the ``range`` function would help in this situation as we can use it to loop over each index in ``haystack`` * The only catch is that we need to actually index ``haystack`` .. code-block:: python :linenos: def index_of(needle, haystack): haystack_length = len(haystack) for i in range(haystack_length): if haystack[i] == needle: return i return -1 * To make what is going on a little clearer, consider the following example .. code-block:: python :linenos: another_list = ["a", "b", "c", "d", "e"] for i in range(len(another_list)): print(i, another_list[i]) # Results in # 0 a # 1 b # 2 c # 3 d # 4 e * This loop prints out the index (``i``) along with the element at the given index (``another_list[i]``) * This functionality is quite common and Python even provides a shorthand for achieving it --- ``enumerate`` .. code-block:: python :linenos: another_list = ["a", "b", "c", "d", "e"] for i, element in enumerate(another_list): print(i, element) # Results in # 0 a # 1 b # 2 c # 3 d # 4 e * Here there is no need to actually index the list since the ``element`` variable already has the value ``another_list[i]`` For Next Class ============== * Read `Chapter 14 of the text `_ * Read `Chapter 15 of the text (only lightly though) `_