{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "bb93f537-c87a-4fe9-bdd6-09beb433a190",
   "metadata": {
    "editable": true,
    "slideshow": {
     "slide_type": ""
    },
    "tags": []
   },
   "source": [
    "# Lists"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "25cf602f-e60d-4369-be94-969e78726be8",
   "metadata": {
    "editable": true,
    "execution": {
     "iopub.execute_input": "2026-08-31T18:38:46.720275Z",
     "iopub.status.busy": "2026-08-31T18:38:46.720170Z",
     "iopub.status.idle": "2026-08-31T18:38:48.204253Z",
     "shell.execute_reply": "2026-08-31T18:38:48.203904Z"
    },
    "slideshow": {
     "slide_type": ""
    },
    "tags": [
     "hide-input",
     "thebe-init",
     "runnable"
    ]
   },
   "outputs": [],
   "source": [
    "import sys\n",
    "from pathlib import Path\n",
    "\n",
    "current = Path.cwd()\n",
    "for parent in [current, *current.parents]:\n",
    "    if (parent / '_config.yml').exists():\n",
    "        project_root = parent  # ← Add project root, not chapters\n",
    "        break\n",
    "else:\n",
    "    project_root = Path.cwd().parent.parent\n",
    "\n",
    "sys.path.insert(0, str(project_root))\n",
    "\n",
    "from shared import thinkpython, diagram, jupyturtle"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4c7e21db",
   "metadata": {},
   "source": [
    "```{contents}\n",
    ":local:\n",
    ":depth: 2\n",
    "```\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "faa5ab38-e69e-46c0-a0df-039c9088c446",
   "metadata": {},
   "source": [
    "We will learn the following about `list`:\n",
    "\n",
    "- features\n",
    "- basic operations\n",
    "- functions\n",
    "- methods\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6d420b6e-a629-4d11-b37d-9c8e353059fc",
   "metadata": {
    "editable": true,
    "slideshow": {
     "slide_type": ""
    },
    "tags": []
   },
   "source": [
    "In Python, a list is a **sequence** type, meaning it is an **ordered** collection of items that can store multiple values in a single variable. Also, a list is a **mutable** sequence. \n",
    "\n",
    "Lists are extremely flexible because they can hold elements of different **data types**, such as numbers, strings, or even other lists, and can be changed (**mutable**) after creation by adding, removing, or modifying items. 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**."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "55ff55a9-add6-424e-837f-61b0361c0bea",
   "metadata": {},
   "source": [
    "Some basic properties of Python lists are as follows: \n",
    "\n",
    "| Property           | Description                                                                 |\n",
    "|--------------------|-----------------------------------------------------------------------------|\n",
    "| **Ordered**        | Elements maintain the order in which they were added and can be accessed by index (starting at 0). |\n",
    "| **Mutable**        | You can change, add, or remove elements after the list is created.           |\n",
    "| **Allows Duplicates** | Lists can contain repeated values without restriction.                    |\n",
    "| **Dynamic Size**   | The length of a list can grow or shrink as elements are added or removed.   |\n",
    "| **Heterogeneous**  | A single list can hold items of different data types (e.g., integers, strings, objects). |"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "acb36491-bf92-40db-8884-1d507a5ea192",
   "metadata": {},
   "source": [
    "## Basic Operations\n",
    "\n",
    "Basic Python list operations include:\n",
    "\n",
    "1. Creating lists: Assignment with `[ ]`\n",
    "2. Indexing (`mylist[0]`, `mylist[-1]`)\n",
    "3. Slicing (`mylist[1:4]`, `mylist[::-1]`)\n",
    "4. Updating (`mylist[0] = 1000`)\n",
    "5. List functions (e.g., `len()`)\n",
    "6. Iterating through lists (for loops, while loops)\n",
    "\n",
    "Because `list` is the name of a built-in function, you should avoid using it as a variable name."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4186bfb6",
   "metadata": {},
   "source": [
    "### Creating Lists\n",
    "\n",
    "The simplest way to create a list is to enclose the elements in square brackets (`[` and `]`), and we usually assign the created list to a variable name. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "e115f08f-7617-455f-9c23-298eb2fef03b",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-08-31T18:38:48.207098Z",
     "iopub.status.busy": "2026-08-31T18:38:48.206923Z",
     "iopub.status.idle": "2026-08-31T18:38:48.208800Z",
     "shell.execute_reply": "2026-08-31T18:38:48.208487Z"
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "numbers = [ 1, 2, 3, 4, 5 ]               ### int list\n",
    "fruits = [ 'apple', 'banana', 'cherry']   ### string list"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4521d8f3",
   "metadata": {},
   "source": [
    "The elements of a list don't have to be the same type. The following list contains a string, a float, an integer, and even another list. This list is therefore **heterogeneous**:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "9e72d76e",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-08-31T18:38:48.210055Z",
     "iopub.status.busy": "2026-08-31T18:38:48.209970Z",
     "iopub.status.idle": "2026-08-31T18:38:48.211384Z",
     "shell.execute_reply": "2026-08-31T18:38:48.211173Z"
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "t = ['spam', 2.0, 5, [10, 20]]"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ab9af5de-af2e-4992-a1c9-4c1ca6f6da11",
   "metadata": {},
   "source": [
    "A list within another list is called a **nested** list, which is important because it lets you represent more complex data structures, such as **tables**, matrices, and provides a stepping stone to understanding **multi-dimensional arrays** for advanced data processing."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "76883a97-c13b-4fae-9f3a-8e870187f7a5",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-08-31T18:38:48.212660Z",
     "iopub.status.busy": "2026-08-31T18:38:48.212593Z",
     "iopub.status.idle": "2026-08-31T18:38:48.214058Z",
     "shell.execute_reply": "2026-08-31T18:38:48.213825Z"
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "nums = [ 1, 2, 3, [4, 5 ] ]"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c709dae7",
   "metadata": {},
   "source": [
    "A list with no elements is called an empty list and can be created with **empty** brackets, `[]`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "8c4c0d99",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-08-31T18:38:48.215394Z",
     "iopub.status.busy": "2026-08-31T18:38:48.215324Z",
     "iopub.status.idle": "2026-08-31T18:38:48.216727Z",
     "shell.execute_reply": "2026-08-31T18:38:48.216512Z"
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "empty = []"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ad8f727f-8de3-4c40-8f0b-89f6120e9e28",
   "metadata": {},
   "source": [
    "### Indexing\n",
    "\n",
    "In Python, list indexing is the process of accessing individual elements within a list using their position. To access an element of a list, we can use the bracket operator. The index of the first element is `0`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "e5ce6c41",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-08-31T18:38:48.217907Z",
     "iopub.status.busy": "2026-08-31T18:38:48.217849Z",
     "iopub.status.idle": "2026-08-31T18:38:48.220318Z",
     "shell.execute_reply": "2026-08-31T18:38:48.220035Z"
    },
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'apple'"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "fruits = [ \"apple\", \"banana\", \"cherry\" ]\n",
    "fruits[0]                                ### 'apple'"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3d82eeb2",
   "metadata": {},
   "source": [
    "List indices work as:\n",
    "\n",
    "1. Python uses **zero-based indexing**, which means the first element has index 0, the second has index 1, and so on.\n",
    "2. Any **integer** expression can be used as an index.\n",
    "3. If you try to read or write an element that does not exist, you get\n",
    "  an `IndexError`.\n",
    "4. If an index has a **negative** value, it counts backward from the end of\n",
    "  the list, beginning with `-1`.\n",
    "\n",
    "With 0-based indexing and negative indexing, list indexing looks like {numref}(list-indexing) below.\n",
    "\n",
    "```{figure} ../../figures/list-indexing.png\n",
    "width: 50%\n",
    "name: list-indexing\n",
    "alt: Python List Indexing with positive and negative indices\n",
    "\n",
    "[Python List Indexing](https://www.geeksforgeeks.org/python/slicing-with-negative-numbers-in-python/): Accessing elements by position\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d4a456a0",
   "metadata": {},
   "source": [
    "Although a list can contain another list, the nested list still counts as a single element -- so in the following list, there are only **4** elements."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "9c529171",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-08-31T18:38:48.221674Z",
     "iopub.status.busy": "2026-08-31T18:38:48.221613Z",
     "iopub.status.idle": "2026-08-31T18:38:48.223283Z",
     "shell.execute_reply": "2026-08-31T18:38:48.223000Z"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "4\n",
      "[10, 20]\n"
     ]
    }
   ],
   "source": [
    "t = ['spam', 2.0, 5, [10, 20]]\n",
    "print(len(t))\n",
    "print(t[3])"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "dceef093",
   "metadata": {},
   "source": [
    "### List Slicing\n",
    "\n",
    "Things to know about list slicing:\n",
    "- Slicing returns a **new list** from a portion of the elements of the original list.\n",
    "- The list slicing syntax uses colons (`:`) and index parameters inside the square brackets following the list.\n",
    "- There are 3 index **parameters** in the square brackets, and they are all optional:\n",
    "  - **start**,\n",
    "  - **stop**,\n",
    "  - **step**.\n",
    "    We mostly use only the start and stop parameters. \n",
    "- The start index is **inclusive**, but the stop index is **exclusive**; for example, `nums[1:3]` would return a new list containing the elements index[1] and index[2], but not num[3] because it is exclusive.\n",
    "\n",
    "\n",
    "The following example selects the second and third elements from a list of four letters."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "f690553f",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-08-31T18:38:48.224507Z",
     "iopub.status.busy": "2026-08-31T18:38:48.224448Z",
     "iopub.status.idle": "2026-08-31T18:38:48.226179Z",
     "shell.execute_reply": "2026-08-31T18:38:48.225941Z"
    },
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['b', 'c']"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "letters = ['a', 'b', 'c', 'd']\n",
    "letters[1:3]                            ### ['b', 'c']"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ed713da8",
   "metadata": {},
   "source": [
    "If you omit the first index, the slice starts at the beginning."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "d19f6b3c",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-08-31T18:38:48.227326Z",
     "iopub.status.busy": "2026-08-31T18:38:48.227255Z",
     "iopub.status.idle": "2026-08-31T18:38:48.228931Z",
     "shell.execute_reply": "2026-08-31T18:38:48.228728Z"
    },
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['a', 'b']"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "letters[:2]                             ### ['a', 'b']"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "988512da",
   "metadata": {},
   "source": [
    "If you omit the second, the slice goes to the end."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "773dfb3b",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-08-31T18:38:48.230179Z",
     "iopub.status.busy": "2026-08-31T18:38:48.230100Z",
     "iopub.status.idle": "2026-08-31T18:38:48.231952Z",
     "shell.execute_reply": "2026-08-31T18:38:48.231725Z"
    },
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['c', 'd']"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "letters[2:]                             ### ['c', 'd']"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7c2892eb",
   "metadata": {},
   "source": [
    "So if you omit both, the slice is a copy of the whole list."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "187d9495",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-08-31T18:38:48.233168Z",
     "iopub.status.busy": "2026-08-31T18:38:48.233097Z",
     "iopub.status.idle": "2026-08-31T18:38:48.234858Z",
     "shell.execute_reply": "2026-08-31T18:38:48.234634Z"
    },
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['a', 'b', 'c', 'd']"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "letters[:]                              ### ['a', 'b', 'c', 'd']"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "17252f29-07a7-4890-9216-0db2ccf932c4",
   "metadata": {},
   "source": [
    "### Modification\n",
    "\n",
    "Unlike strings, lists are **mutable**. When the bracket operator appears on the left side of an assignment, it identifies the element of the list that will be assigned."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "2952e91d",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-08-31T18:38:48.236002Z",
     "iopub.status.busy": "2026-08-31T18:38:48.235941Z",
     "iopub.status.idle": "2026-08-31T18:38:48.237899Z",
     "shell.execute_reply": "2026-08-31T18:38:48.237651Z"
    },
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['avocado', 'banana', 'cherry']"
      ]
     },
     "execution_count": 12,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "fruits = [ \"apple\", \"banana\", \"cherry\" ]\n",
    "fruits[0] = \"avocado\"\n",
    "fruits                                 ### fruits[0] is now 'avocado.'"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "355ea8fd-e191-4f7d-b020-a57a35387aeb",
   "metadata": {
    "editable": true,
    "slideshow": {
     "slide_type": ""
    },
    "tags": []
   },
   "source": [
    "### List operations\n",
    "\n",
    "List operators like `in`, `+`, and `*` are used on lists as well.\n",
    "\n",
    "The **`in`** operator works on lists; it checks whether a given element appears in the list."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "id": "c2bbb5a6",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-08-31T18:38:48.239169Z",
     "iopub.status.busy": "2026-08-31T18:38:48.239104Z",
     "iopub.status.idle": "2026-08-31T18:38:48.240947Z",
     "shell.execute_reply": "2026-08-31T18:38:48.240762Z"
    },
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 13,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "fruits = [ \"apple\", \"banana\", \"cherry\" ]\n",
    "'banana' in fruits              ### True"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7a8f87d0-de6a-429e-a735-1451c8fa78ac",
   "metadata": {},
   "source": [
    "And `10` is not considered to be an element of `t` because it is an element of a nested list, not `t`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "id": "0f060c18",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-08-31T18:38:48.242263Z",
     "iopub.status.busy": "2026-08-31T18:38:48.242188Z",
     "iopub.status.idle": "2026-08-31T18:38:48.244030Z",
     "shell.execute_reply": "2026-08-31T18:38:48.243848Z"
    },
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "False"
      ]
     },
     "execution_count": 14,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "t = ['spam', 2.0, 5, [10, 20]]\n",
    "10 in t                         ### False"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d5fb60c7-31e1-4dd4-8223-df4ff833b467",
   "metadata": {},
   "source": [
    "The `+` operator concatenates lists."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "id": "bc2f3d5b",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-08-31T18:38:48.245254Z",
     "iopub.status.busy": "2026-08-31T18:38:48.245188Z",
     "iopub.status.idle": "2026-08-31T18:38:48.247083Z",
     "shell.execute_reply": "2026-08-31T18:38:48.246833Z"
    },
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[1, 2, 3, 4]"
      ]
     },
     "execution_count": 15,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "t1 = [1, 2]\n",
    "t2 = [3, 4]\n",
    "t1 + t2                         ### [1, 2, 3, 4]"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8eaee60c-c873-4b27-835e-ea24ca354fe9",
   "metadata": {},
   "source": [
    "The `*` operator repeats a list a given number of times."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "id": "ef7cd669",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-08-31T18:38:48.248415Z",
     "iopub.status.busy": "2026-08-31T18:38:48.248337Z",
     "iopub.status.idle": "2026-08-31T18:38:48.250076Z",
     "shell.execute_reply": "2026-08-31T18:38:48.249842Z"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "['spam', 'spam', 'spam', 'spam']\n",
      "[1, 2, 3, 1, 2, 3, 1, 2, 3]\n"
     ]
    }
   ],
   "source": [
    "spams = ['spam'] * 4                    ### ['spam', 'spam', 'spam', 'spam']\n",
    "nums = [ 1, 2, 3 ] * 3                 ### [1, 2, 3, 1, 2, 3, 1, 2, 3]\n",
    "\n",
    "print(spams)\n",
    "print(nums)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "id": "ch02-lists-basic-exercise-q",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-08-31T18:38:48.251414Z",
     "iopub.status.busy": "2026-08-31T18:38:48.251344Z",
     "iopub.status.idle": "2026-08-31T18:38:48.252908Z",
     "shell.execute_reply": "2026-08-31T18:38:48.252711Z"
    },
    "tags": [
     "thebe-interactive"
    ]
   },
   "outputs": [],
   "source": [
    "### Exercise: Index, Slice, and Modify a List\n",
    "# Use indexing, slicing, and assignment with the list below.\n",
    "# Replace \"Ops\" with \"Operations\".\n",
    "# Print exactly:\n",
    "# First department: Sales\n",
    "# First two: ['Sales', 'HR']\n",
    "# Updated departments: ['Sales', 'HR', 'Operations', 'Finance']\n",
    "departments = [\"Sales\", \"HR\", \"Ops\", \"Finance\"]\n",
    "### Your code starts here.\n",
    "\n",
    "\n",
    "\n",
    "### Your code ends here."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "id": "ch02-lists-basic-exercise-a",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-08-31T18:38:48.254071Z",
     "iopub.status.busy": "2026-08-31T18:38:48.254014Z",
     "iopub.status.idle": "2026-08-31T18:38:48.255635Z",
     "shell.execute_reply": "2026-08-31T18:38:48.255370Z"
    },
    "tags": [
     "hide-input"
    ]
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "First department: Sales\n",
      "First two: ['Sales', 'HR']\n",
      "Updated departments: ['Sales', 'HR', 'Operations', 'Finance']\n"
     ]
    }
   ],
   "source": [
    "### Solution\n",
    "departments = [\"Sales\", \"HR\", \"Ops\", \"Finance\"]\n",
    "\n",
    "first_department = departments[0]\n",
    "first_two = departments[:2]\n",
    "departments[2] = \"Operations\"\n",
    "\n",
    "print(\"First department:\", first_department)\n",
    "print(\"First two:\", first_two)\n",
    "print(\"Updated departments:\", departments)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ae8903c5-192b-4353-8602-c237d1b06e13",
   "metadata": {},
   "source": [
    "## List Functions\n",
    "\n",
    "Some Python built-in functions are useful when working with lists:\n",
    "\n",
    "- **len()**\n",
    "- min()\n",
    "- max()\n",
    "- sum()\n",
    "- sorted()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3ce71741",
   "metadata": {},
   "source": [
    "The `len` function returns the length of a list. The length of an empty list is `0`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "id": "6f7293f2-2100-40fb-81f0-0a18dd2377f0",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-08-31T18:38:48.256952Z",
     "iopub.status.busy": "2026-08-31T18:38:48.256882Z",
     "iopub.status.idle": "2026-08-31T18:38:48.258451Z",
     "shell.execute_reply": "2026-08-31T18:38:48.258223Z"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "3\n",
      "0\n"
     ]
    }
   ],
   "source": [
    "fruits = ['apple', 'banana', 'cherry']\n",
    "empty = []\n",
    "\n",
    "print(len(fruits))\n",
    "print(len(empty))"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "id": "202e4515-8b15-4960-96e6-fdfb982e42c8",
   "metadata": {},
   "source": [
    "No other mathematical operators work with lists, but the built-in function `sum` adds up the elements. And `min` and `max` find the smallest and largest elements."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "id": "5f3459a8-49a4-4d46-a76c-f80df168cb1f",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-08-31T18:38:48.259882Z",
     "iopub.status.busy": "2026-08-31T18:38:48.259808Z",
     "iopub.status.idle": "2026-08-31T18:38:48.261408Z",
     "shell.execute_reply": "2026-08-31T18:38:48.261140Z"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "15\n",
      "1\n",
      "5\n"
     ]
    }
   ],
   "source": [
    "nums = [1, 2, 3, 4 ,5 ]\n",
    "\n",
    "print(sum(nums))                         \n",
    "print(min(nums))                         ### 1\n",
    "print(max(nums))                         ### 5"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "id": "d85ccf73-e7be-4586-add4-7c52396ee69e",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-08-31T18:38:48.262565Z",
     "iopub.status.busy": "2026-08-31T18:38:48.262485Z",
     "iopub.status.idle": "2026-08-31T18:38:48.263954Z",
     "shell.execute_reply": "2026-08-31T18:38:48.263723Z"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[1, 2, 3, 4, 5]\n",
      "[1, 5, 3, 4, 2]\n"
     ]
    }
   ],
   "source": [
    "nums = [ 1, 5, 3, 4, 2 ]\n",
    "nums_sort = sorted(nums)   ### save to nums_sort\n",
    "\n",
    "print(nums_sort)\n",
    "print(nums)               ### original list unchanged"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "id": "ch02-lists-functions-exercise-q",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-08-31T18:38:48.264953Z",
     "iopub.status.busy": "2026-08-31T18:38:48.264899Z",
     "iopub.status.idle": "2026-08-31T18:38:48.266183Z",
     "shell.execute_reply": "2026-08-31T18:38:48.265991Z"
    },
    "tags": [
     "thebe-interactive"
    ]
   },
   "outputs": [],
   "source": [
    "### Exercise: Use List Functions\n",
    "# Use built-in functions to summarize weekly customer counts.\n",
    "# Print exactly:\n",
    "# Days tracked: 5\n",
    "# Total customers: 600\n",
    "# Highest day: 160\n",
    "# Lowest day: 80\n",
    "customers = [120, 95, 145, 160, 80]\n",
    "### Your code starts here.\n",
    "\n",
    "\n",
    "\n",
    "### Your code ends here."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "id": "ch02-lists-functions-exercise-a",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-08-31T18:38:48.267234Z",
     "iopub.status.busy": "2026-08-31T18:38:48.267164Z",
     "iopub.status.idle": "2026-08-31T18:38:48.269213Z",
     "shell.execute_reply": "2026-08-31T18:38:48.268916Z"
    },
    "tags": [
     "hide-input"
    ]
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Days tracked: 5\n",
      "Total customers: 600\n",
      "Highest day: 160\n",
      "Lowest day: 80\n"
     ]
    }
   ],
   "source": [
    "### Solution\n",
    "customers = [120, 95, 145, 160, 80]\n",
    "\n",
    "print(\"Days tracked:\", len(customers))\n",
    "print(\"Total customers:\", sum(customers))\n",
    "print(\"Highest day:\", max(customers))\n",
    "print(\"Lowest day:\", min(customers))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f721de26",
   "metadata": {},
   "source": [
    "## List Methods\n",
    "\n",
    "Python also has a set of built-in methods that you can use on list objects. Commonly used list methods include:\n",
    "\n",
    "- append()\n",
    "- extend()\n",
    "- pop()\n",
    "- remove()\n",
    "- sort() \n",
    "- reverse() \n",
    "- index() \n",
    "- count() \n",
    "- insert() \n",
    "- clear() \n",
    "- copy()\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f7c265dd-dff1-4d25-8140-31285b75d5c6",
   "metadata": {},
   "source": [
    "Use the **dot operator** (`.`) to access the methods a list object has. Just type the name of the list, followed by `.`, and hit the Tab key:\n",
    "\n",
    "```python\n",
    ">>> nums = [ 1, 2, 3 ]\n",
    ">>> nums.\n",
    "t1.append(    t1.copy()     t1.extend(    t1.insert(    t1.remove(    t1.sort(\n",
    "t1.clear()    t1.count(     t1.index(     t1.pop(       t1.reverse()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7425353c",
   "metadata": {},
   "source": [
    "### `append()`\n",
    "Python provides methods that operate on lists. For example, `append`\n",
    "adds a new element to the end of a list:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "id": "6db6e689",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-08-31T18:38:48.270548Z",
     "iopub.status.busy": "2026-08-31T18:38:48.270492Z",
     "iopub.status.idle": "2026-08-31T18:38:48.272056Z",
     "shell.execute_reply": "2026-08-31T18:38:48.271740Z"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "['a', 'b', 'c', 'd']\n",
      "['a', 'b', 'c', 'd', 'e']\n"
     ]
    }
   ],
   "source": [
    "letters = ['a', 'b', 'c', 'd']\n",
    "print(letters)        ### ['a', 'b', 'c', 'd']\n",
    "\n",
    "letters.append(\"e\")\n",
    "print(letters)        ## ['a', 'b', 'c', 'd', 'e']"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1fbc0618",
   "metadata": {},
   "source": [
    "### `extend()`\n",
    "`extend` takes a **list as an argument** (not values) and appends all of the elements to the original list:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "id": "30b89348",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-08-31T18:38:48.273141Z",
     "iopub.status.busy": "2026-08-31T18:38:48.273078Z",
     "iopub.status.idle": "2026-08-31T18:38:48.274458Z",
     "shell.execute_reply": "2026-08-31T18:38:48.274292Z"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "['a', 'b', 'c', 'd', 'e', 'f', 'g']\n"
     ]
    }
   ],
   "source": [
    "two_letters = ['f', 'g']\n",
    "letters.extend(two_letters)\n",
    "print(letters)        ### ['a', 'b', 'c', 'd', 'e', 'f', 'g']"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2a8578f5",
   "metadata": {},
   "source": [
    "### `pop()`\n",
    "There are two methods that remove elements from a list: pop() and remove()\n",
    "If you know the index of the element you want, you can use `pop`: \n",
    "- If you provide an **index** as the argument, pop() **removes and returns** the element at that index.\n",
    "- If you do not provide an index as an argument, pop() removes and returns the ***last** element in the list."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "id": "70deb4c8",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-08-31T18:38:48.276053Z",
     "iopub.status.busy": "2026-08-31T18:38:48.275973Z",
     "iopub.status.idle": "2026-08-31T18:38:48.278083Z",
     "shell.execute_reply": "2026-08-31T18:38:48.277861Z"
    },
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[1, 3, 4]"
      ]
     },
     "execution_count": 26,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "nums = [1, 2, 3, 4 ,5]\n",
    "nums.pop(1)                 ### pop(1) removes and returns the 2nd element in list. \n",
    "nums\n",
    "nums.pop()                  ### pop() removes & returns the last element.\n",
    "nums"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "097758cc",
   "metadata": {},
   "source": [
    "### `remove()`\n",
    "On the other hand, if you know the element you want to remove (but not the index), you can use `remove`:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "id": "dde122b0",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-08-31T18:38:48.279358Z",
     "iopub.status.busy": "2026-08-31T18:38:48.279291Z",
     "iopub.status.idle": "2026-08-31T18:38:48.281528Z",
     "shell.execute_reply": "2026-08-31T18:38:48.281117Z"
    },
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[1, 2, 4, 5]"
      ]
     },
     "execution_count": 27,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "nums = [1, 2, 3, 4 ,5]\n",
    "nums.remove(3)\n",
    "nums"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8bd3c7cf",
   "metadata": {},
   "source": [
    "If the element you ask for is not in the list, that's a ValueError."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "id": "1ca145fc-815a-4b00-91bb-54fd45da9c91",
   "metadata": {
    "editable": true,
    "execution": {
     "iopub.execute_input": "2026-08-31T18:38:48.282966Z",
     "iopub.status.busy": "2026-08-31T18:38:48.282882Z",
     "iopub.status.idle": "2026-08-31T18:38:48.285029Z",
     "shell.execute_reply": "2026-08-31T18:38:48.284835Z"
    },
    "slideshow": {
     "slide_type": ""
    },
    "tags": []
   },
   "outputs": [
    {
     "ename": "ValueError",
     "evalue": "list.remove(x): x not in list",
     "output_type": "error",
     "traceback": [
      "\u001b[31mValueError\u001b[39m\u001b[31m:\u001b[39m list.remove(x): x not in list\n"
     ]
    }
   ],
   "source": [
    "%%expect ValueError\n",
    "\n",
    "nums = [1, 2, 4, 5]\n",
    "nums.remove(6)        ### This will raise a ValueError because 6 is not in the list."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "24c0a09b-e475-4a4e-9759-ba1b7bd8c6e5",
   "metadata": {},
   "source": [
    "### `sort()`\n",
    "\n",
    "The sort() function:\n",
    "- sorts the original list in-place\n",
    "- modifies the original list permanently\n",
    "- returns `None` (save to nothing)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "id": "28516f27-19a7-4c31-811d-5b7754c1c902",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-08-31T18:38:48.286149Z",
     "iopub.status.busy": "2026-08-31T18:38:48.286067Z",
     "iopub.status.idle": "2026-08-31T18:38:48.287684Z",
     "shell.execute_reply": "2026-08-31T18:38:48.287506Z"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "None\n",
      "[1, 2, 3, 4, 5]\n"
     ]
    }
   ],
   "source": [
    "nums = [ 1, 5, 3, 4, 2 ]\n",
    "nums_sort = nums.sort()   ### save to nothing\n",
    "\n",
    "print(nums_sort)\n",
    "print(nums)               ### original list changed"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "id": "8e0f1644-5c8f-44f6-8182-cc2d4443deb9",
   "metadata": {
    "editable": true,
    "execution": {
     "iopub.execute_input": "2026-08-31T18:38:48.288897Z",
     "iopub.status.busy": "2026-08-31T18:38:48.288775Z",
     "iopub.status.idle": "2026-08-31T18:38:48.290312Z",
     "shell.execute_reply": "2026-08-31T18:38:48.290087Z"
    },
    "slideshow": {
     "slide_type": ""
    },
    "tags": [
     "thebe-interactive"
    ]
   },
   "outputs": [],
   "source": [
    "### Exercise: Append\n",
    "### 1. Create an empty list, call it nums\n",
    "### 2. Use a for loop (with range) to append numbers 0 to 9 to nums\n",
    "### 3. Print the list\n",
    "### Your code starts here\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "### Your code ends here"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "id": "a0fb0b33-2159-4893-b1d1-a362f1bd884c",
   "metadata": {
    "editable": true,
    "execution": {
     "iopub.execute_input": "2026-08-31T18:38:48.291472Z",
     "iopub.status.busy": "2026-08-31T18:38:48.291404Z",
     "iopub.status.idle": "2026-08-31T18:38:48.293051Z",
     "shell.execute_reply": "2026-08-31T18:38:48.292825Z"
    },
    "slideshow": {
     "slide_type": ""
    },
    "tags": [
     "hide-input"
    ]
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]\n"
     ]
    }
   ],
   "source": [
    "### Solution\n",
    "nums = []\n",
    "for i in range(10):\n",
    "    nums.append(i)\n",
    "\n",
    "print(nums)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0a9e99e1",
   "metadata": {},
   "source": [
    "## Lists and strings\n",
    "\n",
    "| function/method | syntax | example |\n",
    "|- |- | - |\n",
    "|list( )  | |\n",
    "|split( )|  |\n",
    "|join( ) |   string.join(iterable) |\n",
    "  \n",
    "A string is a **sequence** of characters, and a list is a **sequence** of values, but a list of characters is not the same as a string. To convert from a string to a list of characters, you can use the `list` function/constructor."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "id": "1b7beba9",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-08-31T18:38:48.294104Z",
     "iopub.status.busy": "2026-08-31T18:38:48.294038Z",
     "iopub.status.idle": "2026-08-31T18:38:48.295559Z",
     "shell.execute_reply": "2026-08-31T18:38:48.295360Z"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "['s', 'p', 'a', 'm']\n",
      "spam\n"
     ]
    }
   ],
   "source": [
    "s = 'spam'  \n",
    "t = list(s)    ### make string sequence 'spam' into a list of its characters\n",
    "print(t)       ### new list ['s', 'p', 'a', 'm']    \n",
    "print(s)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e51efbae-4994-457e-a66a-3aceb164e075",
   "metadata": {},
   "source": [
    "Note that `s` is unchanged. `list(s)` returns a new list, which we save to `t`. This \"unchanging\" behavior is actually a **safety feature** in Python called immutability-style processing. It ensures that you don't accidentally destroy your original data when you just want to see it in a different order."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a3d3fd02",
   "metadata": {},
   "source": [
    "Another example:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "id": "944b7026",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-08-31T18:38:48.296768Z",
     "iopub.status.busy": "2026-08-31T18:38:48.296698Z",
     "iopub.status.idle": "2026-08-31T18:38:48.298406Z",
     "shell.execute_reply": "2026-08-31T18:38:48.298177Z"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "['M', ' ', 'S', '&', 'T']\n",
      "M S&T\n"
     ]
    }
   ],
   "source": [
    "s = 'M S&T'\n",
    "t = list(s)         \n",
    "print(t)            ### ['M', ' ', 'S', '&', 'T']\n",
    "print(s)            ### unchanged"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "bb19079d",
   "metadata": {},
   "source": [
    "The `split` function breaks a string into individual words. If you want to break a string into words, you can use the `split` method:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "id": "a642fbc5",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-08-31T18:38:48.299671Z",
     "iopub.status.busy": "2026-08-31T18:38:48.299594Z",
     "iopub.status.idle": "2026-08-31T18:38:48.301519Z",
     "shell.execute_reply": "2026-08-31T18:38:48.301309Z"
    },
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['apple', 'banana', 'cherry']"
      ]
     },
     "execution_count": 34,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "s = 'apple banana cherry'\n",
    "t = s.split()               ### Split the string into a list of words\n",
    "t                           ### ['pining', 'for', 'the', 'fjords']"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f07ff8cc",
   "metadata": {},
   "source": [
    "An optional argument called a **delimiter** specifies which characters to use as word boundaries. The following example uses a hyphen as a delimiter."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "id": "5b16e688",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-08-31T18:38:48.302662Z",
     "iopub.status.busy": "2026-08-31T18:38:48.302600Z",
     "iopub.status.idle": "2026-08-31T18:38:48.304235Z",
     "shell.execute_reply": "2026-08-31T18:38:48.304039Z"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "['ex', 'parrot']\n",
      "ex-parrot\n"
     ]
    }
   ],
   "source": [
    "s = 'ex-parrot'\n",
    "t = s.split('-')            ### note that this returns a list\n",
    "print(t)                    ### ['ex', 'parrot']\n",
    "print(s)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "18f07d49",
   "metadata": {},
   "source": [
    "If you have a list of strings, you can concatenate them into a single string using **`join`**. `join` is a string **method**, so you have to invoke it on the delimiter and pass the list as an argument."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 36,
   "id": "87492b93",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-08-31T18:38:48.305325Z",
     "iopub.status.busy": "2026-08-31T18:38:48.305255Z",
     "iopub.status.idle": "2026-08-31T18:38:48.307142Z",
     "shell.execute_reply": "2026-08-31T18:38:48.306835Z"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "['BIT,', 'Kummer', 'College,', 'S&T']\n",
      "BIT, Kummer College, S&T\n",
      "<class 'str'>\n"
     ]
    }
   ],
   "source": [
    "delimiter = ' '\n",
    "t = ['BIT,', 'Kummer', 'College,', 'S&T']   ### list\n",
    "s = delimiter.join(t)                       ### string\n",
    "print(t)\n",
    "print(s)\n",
    "print(type(s))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "95f87bff-b152-499c-b709-a4cefa120187",
   "metadata": {},
   "source": [
    "In this case the delimiter is a space character, so `join` puts a space\n",
    "between words. To join strings without spaces, you can use the empty string, `''`, as a delimiter."
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "id": "c5f0cd66-d556-4b6b-9903-b613b1d95004",
   "metadata": {},
   "source": [
    "### Sorting lists\n",
    "\n",
    "- sorted( )\n",
    "\n",
    "Python provides a built-in function, **`sorted`**, that sorts the elements of a list. `sorted` works with any kind of sequence, not just lists. So we can sort the letters in a string like this."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 37,
   "id": "3df014ee-720f-4944-b0a9-47dbaf740d47",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-08-31T18:38:48.308425Z",
     "iopub.status.busy": "2026-08-31T18:38:48.308346Z",
     "iopub.status.idle": "2026-08-31T18:38:48.310141Z",
     "shell.execute_reply": "2026-08-31T18:38:48.309922Z"
    },
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['e', 'e', 'l', 'r', 's', 't', 't']"
      ]
     },
     "execution_count": 37,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "sorted('letters')"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3da8de24-8c70-44a2-baa5-8f742b9ac822",
   "metadata": {},
   "source": [
    "The result is a list. To convert the list to a string, we can use **`join`**. With an empty string as the delimiter, the elements of the list are joined with nothing between them."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 38,
   "id": "a3d873aa-b3a6-4f8c-880f-953a4d0d2b62",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-08-31T18:38:48.311207Z",
     "iopub.status.busy": "2026-08-31T18:38:48.311147Z",
     "iopub.status.idle": "2026-08-31T18:38:48.312879Z",
     "shell.execute_reply": "2026-08-31T18:38:48.312661Z"
    },
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'eelrstt'"
      ]
     },
     "execution_count": 38,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "''.join(sorted('letters'))     ### empty delimiter"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 39,
   "id": "24e93abe-5e92-4690-bacb-19933e48b182",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-08-31T18:38:48.314034Z",
     "iopub.status.busy": "2026-08-31T18:38:48.313938Z",
     "iopub.status.idle": "2026-08-31T18:38:48.315922Z",
     "shell.execute_reply": "2026-08-31T18:38:48.315689Z"
    },
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'e-e-l-r-s-t-t'"
      ]
     },
     "execution_count": 39,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "'-'.join(sorted('letters'))    ### '-' as delimiter"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0f676eb7-b84b-4c95-9ef1-5a345b79f1d8",
   "metadata": {},
   "source": [
    "Another example of sorted function:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 40,
   "id": "24f9bc80-4f53-4678-8fdf-b24ac97986a5",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-08-31T18:38:48.317221Z",
     "iopub.status.busy": "2026-08-31T18:38:48.317147Z",
     "iopub.status.idle": "2026-08-31T18:38:48.318717Z",
     "shell.execute_reply": "2026-08-31T18:38:48.318527Z"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "['a', 'b', 'c', 'd']\n",
      "['c', 'a', 'b', 'd']\n"
     ]
    }
   ],
   "source": [
    "scramble = ['c', 'a', 'b', 'd']\n",
    "scrambled = sorted(scramble)\n",
    "print(scrambled)\n",
    "print(scramble)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "81fad5f5",
   "metadata": {},
   "source": [
    "The original list `scramble` is **unchanged**."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "eedcbdec-57e8-4dd6-ab8a-0ab0d81be741",
   "metadata": {},
   "source": [
    "Comparing with the **`sort()`** method, the original list is changed:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 41,
   "id": "0a82fcf5-32c9-4272-91dd-97d0e74bf06f",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-08-31T18:38:48.319849Z",
     "iopub.status.busy": "2026-08-31T18:38:48.319793Z",
     "iopub.status.idle": "2026-08-31T18:38:48.321314Z",
     "shell.execute_reply": "2026-08-31T18:38:48.321134Z"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "['a', 'b', 'c', 'd']\n"
     ]
    }
   ],
   "source": [
    "scramble = ['c', 'a', 'b', 'd']\n",
    "scramble.sort()       ### no return\n",
    "print(scramble)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 42,
   "id": "ch02-lists-strings-exercise-q",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-08-31T18:38:48.322372Z",
     "iopub.status.busy": "2026-08-31T18:38:48.322310Z",
     "iopub.status.idle": "2026-08-31T18:38:48.323613Z",
     "shell.execute_reply": "2026-08-31T18:38:48.323404Z"
    },
    "tags": [
     "thebe-interactive"
    ]
   },
   "outputs": [],
   "source": [
    "### Exercise: Split and Join Text\n",
    "# Split the comma-separated text into a list, sort it, and join it with semicolons.\n",
    "# Print exactly:\n",
    "# Channels: ['email', 'phone', 'web']\n",
    "# Report: email; phone; web\n",
    "channel_text = \"web,email,phone\"\n",
    "### Your code starts here.\n",
    "\n",
    "\n",
    "\n",
    "### Your code ends here."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 43,
   "id": "ch02-lists-strings-exercise-a",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-08-31T18:38:48.325008Z",
     "iopub.status.busy": "2026-08-31T18:38:48.324929Z",
     "iopub.status.idle": "2026-08-31T18:38:48.326617Z",
     "shell.execute_reply": "2026-08-31T18:38:48.326405Z"
    },
    "tags": [
     "hide-input"
    ]
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Channels: ['email', 'phone', 'web']\n",
      "Report: email; phone; web\n"
     ]
    }
   ],
   "source": [
    "### Solution\n",
    "channel_text = \"web,email,phone\"\n",
    "\n",
    "channels = channel_text.split(\",\")\n",
    "channels.sort()\n",
    "report = \"; \".join(channels)\n",
    "\n",
    "print(\"Channels:\", channels)\n",
    "print(\"Report:\", report)"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "id": "94a0301c-b181-4186-8b2f-a4c66d5e808c",
   "metadata": {},
   "source": [
    "## Objects and Values\n",
    "\n",
    "If we run these assignment statements below to create `a` and `b`. We know that `a` and `b` both refer to a string object (a **literal value**), but we don't know whether they refer to the _same_ string. We can use \n",
    "\n",
    "- equivalency comparison (`==`),\n",
    "- object identity comparison (`is`), and\n",
    "- `id()` to test this relationship."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 44,
   "id": "33c9aeaa",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-08-31T18:38:48.327647Z",
     "iopub.status.busy": "2026-08-31T18:38:48.327590Z",
     "iopub.status.idle": "2026-08-31T18:38:48.329129Z",
     "shell.execute_reply": "2026-08-31T18:38:48.328931Z"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "True\n",
      "True\n",
      "4568078000\n",
      "4568078000\n"
     ]
    }
   ],
   "source": [
    "a = 'banana'\n",
    "b = 'banana'\n",
    "\n",
    "print(a == b)\n",
    "print(a is b)\n",
    "\n",
    "print(id(a))\n",
    "print(id(b))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "955ae648",
   "metadata": {},
   "source": [
    "In the example above, Python only created **one string object**, and both `a` and `b` refer to it. "
   ]
  },
  {
   "cell_type": "markdown",
   "id": "14da539c-6f89-47d9-a500-08f595211e7c",
   "metadata": {},
   "source": [
    "Now let us create two lists and perform the same tests."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 45,
   "id": "00a9e5c6",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-08-31T18:38:48.330168Z",
     "iopub.status.busy": "2026-08-31T18:38:48.330087Z",
     "iopub.status.idle": "2026-08-31T18:38:48.331772Z",
     "shell.execute_reply": "2026-08-31T18:38:48.331567Z"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "True\n",
      "False\n",
      "4581874624\n",
      "4581870208\n"
     ]
    }
   ],
   "source": [
    "c = [ 1, 2, 3 ]\n",
    "d = [ 1, 2 ,3 ]\n",
    "\n",
    "print(c == d)\n",
    "print(c is d)\n",
    "\n",
    "print(id(c))\n",
    "print(id(d))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0c52629e-8a09-4657-8e91-3d1bd95584da",
   "metadata": {},
   "source": [
    "We see that `c` and `d` are lists and they are **two different objects**.\n",
    "\n",
    "In this case we would say that the two lists are **equivalent**, because they have the same elements, but not **identical**, because they are not the same object. If two objects are identical, they are also equivalent, but if they are equivalent, they are not necessarily identical."
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "id": "432f604d-fb4e-4131-9dba-066a790b9600",
   "metadata": {},
   "source": [
    "## Aliasing\n",
    "\n",
    "If `num_a` refers to an object and you assign `num_b = num_a`, then both variables refer to the **same object**.\n",
    "\n",
    "The association of a variable with an object is called a **reference**. When a variable refers to an object, it simply points to that object in memory; it does **not** store a **copy** of the object.\n",
    "\n",
    "If an object has more than one reference, we say the object is **aliased**. This means multiple variable names point to the same exact object. If that object is mutable, changing it through one reference will affect what the other reference sees. In other words, different names, same object. This is critical in data science—modifying a DataFrame variable that's aliased to another will affect both. We'll revisit this with NumPy and Pandas."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 46,
   "id": "45cb2424",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-08-31T18:38:48.332769Z",
     "iopub.status.busy": "2026-08-31T18:38:48.332715Z",
     "iopub.status.idle": "2026-08-31T18:38:48.334457Z",
     "shell.execute_reply": "2026-08-31T18:38:48.334205Z"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "True\n",
      "True\n",
      "4581878464\n",
      "4581878464\n"
     ]
    }
   ],
   "source": [
    "nums_a = [ 1, 2, 3, 4, 5 ]\n",
    "nums_b = nums_a\n",
    "\n",
    "print(nums_a == nums_b)\n",
    "print(nums_a is nums_b)\n",
    "print(id(nums_a))\n",
    "print(id(nums_b))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "641ca4f6-3d57-4eaf-87f5-8abe9765ffbd",
   "metadata": {},
   "source": [
    "Now let's update `nums_b`:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 47,
   "id": "d60262a8",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-08-31T18:38:48.335749Z",
     "iopub.status.busy": "2026-08-31T18:38:48.335674Z",
     "iopub.status.idle": "2026-08-31T18:38:48.337414Z",
     "shell.execute_reply": "2026-08-31T18:38:48.337238Z"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[1000, 2, 3, 4, 5]\n",
      "[1000, 2, 3, 4, 5]\n"
     ]
    }
   ],
   "source": [
    "nums_a = [1, 2, 3, 4, 5]   # nums_a refers to a list object\n",
    "nums_b = nums_a            # nums_b refers to the *same* list (alias)\n",
    "\n",
    "nums_a[0] = 1000           # modify through nums_a\n",
    "\n",
    "print(nums_a)  # [1000, 2, 3, 4, 5]\n",
    "print(nums_b)  # [1000, 2, 3, 4, 5] → also changed, because it's the same object"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9087c538-6437-42e1-8856-365667d3f3ba",
   "metadata": {},
   "source": [
    "So we would say that `nums_a` \"sees\" this update to 1,000. Although this behavior can be useful, it is error-prone. In general, it is safer to avoid aliasing when you are working with mutable objects."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "355ef07e-4727-42b1-872b-3b19785fffe1",
   "metadata": {},
   "source": [
    "Aliasing happens when you assign a list to a new variable using the assignment `=` operator (e.g., `list_b = list_a`). In this case, both variables point to the same object in memory. If you change one, you change both because they are essentially just two names for the same thing.\n",
    "\n",
    "However, you can save a list under a different variable name without compromising the original; you just need to create a **copy** rather than an alias."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3747ef44-597f-4991-b026-7105d1fe224e",
   "metadata": {
    "editable": true,
    "slideshow": {
     "slide_type": ""
    },
    "tags": []
   },
   "source": [
    "For immutable objects like strings, aliasing is less of a problem.\n",
    "In this example:\n",
    "\n",
    "```python\n",
    "string_a = 'banana'\n",
    "string_b = 'banana'\n",
    "```\n",
    "\n",
    "It almost never makes a difference whether `a` and `b` refer to the same\n",
    "string or not."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 48,
   "id": "ch02-lists-aliasing-exercise-q",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-08-31T18:38:48.338544Z",
     "iopub.status.busy": "2026-08-31T18:38:48.338479Z",
     "iopub.status.idle": "2026-08-31T18:38:48.339858Z",
     "shell.execute_reply": "2026-08-31T18:38:48.339666Z"
    },
    "tags": [
     "thebe-interactive"
    ]
   },
   "outputs": [],
   "source": [
    "### Exercise: Avoid an Aliasing Surprise\n",
    "# Make a copy before modifying a list.\n",
    "# The original list should stay unchanged.\n",
    "# Print exactly:\n",
    "# Original: ['draft', 'review']\n",
    "# Copy: ['draft', 'review', 'approved']\n",
    "original_statuses = [\"draft\", \"review\"]\n",
    "### Your code starts here.\n",
    "\n",
    "\n",
    "\n",
    "### Your code ends here."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 49,
   "id": "ch02-lists-aliasing-exercise-a",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-08-31T18:38:48.340768Z",
     "iopub.status.busy": "2026-08-31T18:38:48.340713Z",
     "iopub.status.idle": "2026-08-31T18:38:48.342152Z",
     "shell.execute_reply": "2026-08-31T18:38:48.341951Z"
    },
    "tags": [
     "hide-input"
    ]
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Original: ['draft', 'review']\n",
      "Copy: ['draft', 'review', 'approved']\n"
     ]
    }
   ],
   "source": [
    "### Solution\n",
    "original_statuses = [\"draft\", \"review\"]\n",
    "copy_statuses = original_statuses.copy()\n",
    "copy_statuses.append(\"approved\")\n",
    "\n",
    "print(\"Original:\", original_statuses)\n",
    "print(\"Copy:\", copy_statuses)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "95fc2034-71fc-4b6f-8f35-6a84a8eb6d2f",
   "metadata": {
    "editable": true,
    "slideshow": {
     "slide_type": ""
    },
    "tags": []
   },
   "source": [
    "## Making a word list\n",
    "\n",
    "The word-list examples in this section use `data/words.txt` from the project root. The setup cell below points `words_path` to that shared data file."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 50,
   "id": "5c86cd0d-779f-42d0-a986-3eb1761dcdb4",
   "metadata": {
    "editable": true,
    "execution": {
     "iopub.execute_input": "2026-08-31T18:38:48.343215Z",
     "iopub.status.busy": "2026-08-31T18:38:48.343131Z",
     "iopub.status.idle": "2026-08-31T18:38:48.345089Z",
     "shell.execute_reply": "2026-08-31T18:38:48.344845Z"
    },
    "slideshow": {
     "slide_type": ""
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "from pathlib import Path\n",
    "\n",
    "current = Path.cwd()\n",
    "for parent in [current, *current.parents]:\n",
    "    if (parent / \"_config.yml\").exists():\n",
    "        project_root = parent\n",
    "        break\n",
    "else:\n",
    "    project_root = Path.cwd().parent.parent\n",
    "\n",
    "words_path = project_root / \"data\" / \"words.txt\""
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e8a11f57-c96f-491a-bcc6-8e7b8316e7e1",
   "metadata": {
    "editable": true,
    "slideshow": {
     "slide_type": ""
    },
    "tags": []
   },
   "source": [
    "To read a file in Python, we have three common ways:\n",
    "\n",
    "1. Read the whole file\n",
    "2. Read line by line\n",
    "3. Read all lines into a list\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e807b512-6ddf-4166-a8c2-3a29254d1b2b",
   "metadata": {
    "editable": true,
    "slideshow": {
     "slide_type": ""
    },
    "tags": []
   },
   "source": [
    "### Read whole file\n",
    "To read the whole file, the common syntax is to use the `with` keyword to create a file object called `f` as seen below. Note that:\n",
    "\n",
    "- The advantage of using `with` is that the file will auomatically **close** when the block ends so no need to call `f.close()` to close the file pipeline.\n",
    "- The file is represented as one string and you can see the `\\n` characters after each string, which represent new lines. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 51,
   "id": "464222fe-27aa-420c-98e4-f5ed91c759a5",
   "metadata": {
    "editable": true,
    "execution": {
     "iopub.execute_input": "2026-08-31T18:38:48.346265Z",
     "iopub.status.busy": "2026-08-31T18:38:48.346187Z",
     "iopub.status.idle": "2026-08-31T18:38:48.362111Z",
     "shell.execute_reply": "2026-08-31T18:38:48.361829Z"
    },
    "slideshow": {
     "slide_type": ""
    },
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'aa\\naah\\naahed\\naahing\\naahs\\naal\\naalii\\naaliis\\naals\\naardvark\\naardvarks\\naardwolf\\naardwolves\\naas\\naasvogel\\na'"
      ]
     },
     "execution_count": 51,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "with open(words_path, \"r\") as f:\n",
    "    content = f.read(100)          ### read 100 characters of the WHOLE file because it's too big to display here\n",
    "\n",
    "content\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "573c7b72-8a1b-45db-8b65-94e994dce899",
   "metadata": {
    "editable": true,
    "slideshow": {
     "slide_type": ""
    },
    "tags": []
   },
   "source": [
    "With `print()` function, the `\\n` new line characters are honored. Note this is the `content` variable, which contains only 50 characters of the whole file (fron 'aa' to 'aar') with `\\n` shown as new lines. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 52,
   "id": "46938a24-bb61-4e7f-8ab3-8c696c07b8c8",
   "metadata": {
    "editable": true,
    "execution": {
     "iopub.execute_input": "2026-08-31T18:38:48.363387Z",
     "iopub.status.busy": "2026-08-31T18:38:48.363329Z",
     "iopub.status.idle": "2026-08-31T18:38:48.365150Z",
     "shell.execute_reply": "2026-08-31T18:38:48.364921Z"
    },
    "slideshow": {
     "slide_type": ""
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "aa\n",
      "aah\n",
      "aahed\n",
      "aahing\n",
      "aahs\n",
      "aal\n",
      "aalii\n",
      "aaliis\n",
      "aals\n",
      "aardvark\n",
      "aardvarks\n",
      "aardwolf\n",
      "aardwolves\n",
      "aas\n",
      "aasvogel\n",
      "a\n"
     ]
    }
   ],
   "source": [
    "print(content)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 53,
   "id": "b17807ca",
   "metadata": {
    "editable": true,
    "execution": {
     "iopub.execute_input": "2026-08-31T18:38:48.366302Z",
     "iopub.status.busy": "2026-08-31T18:38:48.366244Z",
     "iopub.status.idle": "2026-08-31T18:38:48.367685Z",
     "shell.execute_reply": "2026-08-31T18:38:48.367456Z"
    },
    "slideshow": {
     "slide_type": ""
    },
    "tags": [
     "thebe-interactive"
    ]
   },
   "outputs": [],
   "source": [
    "### Exercise: \n",
    "# 1. Show the whole content of the file (use print)\n",
    "# 2. Count how many words are in the file (use len)\n",
    "# Your code starts here:\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "# Your code ends here. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 54,
   "id": "c28270a1",
   "metadata": {
    "editable": true,
    "execution": {
     "iopub.execute_input": "2026-08-31T18:38:48.368848Z",
     "iopub.status.busy": "2026-08-31T18:38:48.368785Z",
     "iopub.status.idle": "2026-08-31T18:38:48.371419Z",
     "shell.execute_reply": "2026-08-31T18:38:48.371233Z"
    },
    "slideshow": {
     "slide_type": ""
    },
    "tags": [
     "hide-input"
    ]
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "The length of the file words.txt is 1016511 characters.\n"
     ]
    }
   ],
   "source": [
    "### Solution\n",
    "### Exercise solution: Input hidden\n",
    "\n",
    "with open(words_path, \"r\") as f:\n",
    "    content = f.read()\n",
    "    \n",
    "\n",
    "# print(len(content.split()))\n",
    "print(\"The length of the file words.txt is\", len(content), \"characters.\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "66c3d7a4-1764-4367-83cb-fd30f22a9a2e",
   "metadata": {},
   "source": [
    "### Read by `append`\n",
    "\n",
    "For a data file, instead ofreading the entire file, which is not efficient, it is better to read the file once and put the words in a **list** object. The following code shows how this is done by adding (`append`) one line at a time to build the list `word_list`. \n",
    "\n",
    "Before the loop, the `word_list` is initialized with an empty list.\n",
    "Each time through the loop, the `append` method adds a word to the end.\n",
    "When the loop is done, there are more than 113,000 words in the list.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 55,
   "id": "5672700e-18d3-4990-87a9-9af1bc564446",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-08-31T18:38:48.372785Z",
     "iopub.status.busy": "2026-08-31T18:38:48.372728Z",
     "iopub.status.idle": "2026-08-31T18:38:48.386609Z",
     "shell.execute_reply": "2026-08-31T18:38:48.386260Z"
    },
    "tags": []
   },
   "outputs": [],
   "source": [
    "word_list = []\n",
    "\n",
    "for line in open(words_path):\n",
    "    word = line.strip()\n",
    "    word_list.append(word)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "37b4d767-602f-4ec9-b891-56c541b7eadc",
   "metadata": {},
   "source": [
    "We now have a list named `word_list`. Let us take a look at the list (first 10 elements):"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 56,
   "id": "607d398b-8eb8-4945-afd9-1d36f8e93963",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-08-31T18:38:48.387980Z",
     "iopub.status.busy": "2026-08-31T18:38:48.387905Z",
     "iopub.status.idle": "2026-08-31T18:38:48.389683Z",
     "shell.execute_reply": "2026-08-31T18:38:48.389410Z"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "['aa', 'aah', 'aahed', 'aahing', 'aahs', 'aal', 'aalii', 'aaliis', 'aals', 'aardvark']\n"
     ]
    }
   ],
   "source": [
    "print(word_list[:10])"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d97dbb17-0200-47b9-9eab-a9f47c615b1d",
   "metadata": {},
   "source": [
    "We know that we have a lot more than 10 words in this list. The number of elements of this list object can be seen using the **`len()`** function:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 57,
   "id": "37698b6a-5224-4a18-af44-447827ff70be",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-08-31T18:38:48.390870Z",
     "iopub.status.busy": "2026-08-31T18:38:48.390811Z",
     "iopub.status.idle": "2026-08-31T18:38:48.392618Z",
     "shell.execute_reply": "2026-08-31T18:38:48.392430Z"
    },
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "113783"
      ]
     },
     "execution_count": 57,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "len(word_list)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b09c2afb-f952-420b-ad28-07544940d15d",
   "metadata": {},
   "source": [
    "### Read by `readlines`\n",
    "\n",
    "The same thing can be achieved by using `f.readlines()` but `readlines()` returns the entire list into a list at once."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 58,
   "id": "48da2878-e910-428c-b0b6-15eb0a723d60",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-08-31T18:38:48.393733Z",
     "iopub.status.busy": "2026-08-31T18:38:48.393665Z",
     "iopub.status.idle": "2026-08-31T18:38:48.399915Z",
     "shell.execute_reply": "2026-08-31T18:38:48.399692Z"
    },
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['aa\\n',\n",
       " 'aah\\n',\n",
       " 'aahed\\n',\n",
       " 'aahing\\n',\n",
       " 'aahs\\n',\n",
       " 'aal\\n',\n",
       " 'aalii\\n',\n",
       " 'aaliis\\n',\n",
       " 'aals\\n',\n",
       " 'aardvark\\n']"
      ]
     },
     "execution_count": 58,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "with open(words_path, \"r\") as f:\n",
    "    lines = f.readlines()\n",
    "\n",
    "lines[:10]"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a90d895e-339c-4ffa-9e5f-1b0d67e0f9fd",
   "metadata": {},
   "source": [
    "When printing, we see each string element has a new line character `\\n` as shown below: "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 59,
   "id": "d2d38c8b-bc67-4f19-8762-299673bfabba",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-08-31T18:38:48.401065Z",
     "iopub.status.busy": "2026-08-31T18:38:48.400996Z",
     "iopub.status.idle": "2026-08-31T18:38:48.402464Z",
     "shell.execute_reply": "2026-08-31T18:38:48.402257Z"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "['aa\\n', 'aah\\n', 'aahed\\n', 'aahing\\n', 'aahs\\n', 'aal\\n', 'aalii\\n', 'aaliis\\n', 'aals\\n', 'aardvark\\n']\n"
     ]
    }
   ],
   "source": [
    "print(lines[:10])"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a2537a61-dfb3-4bb3-bb29-2bd132ade090",
   "metadata": {},
   "source": [
    "Or, if you do not want to see the `\\n` character:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 60,
   "id": "3034bff9-24d8-40e6-bd25-6b46ff3ba0f3",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-08-31T18:38:48.403649Z",
     "iopub.status.busy": "2026-08-31T18:38:48.403574Z",
     "iopub.status.idle": "2026-08-31T18:38:48.405123Z",
     "shell.execute_reply": "2026-08-31T18:38:48.404932Z"
    },
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "aa\n",
      "aah\n",
      "aahed\n",
      "aahing\n",
      "aahs\n",
      "aal\n",
      "aalii\n",
      "aaliis\n",
      "aals\n",
      "aardvark\n"
     ]
    }
   ],
   "source": [
    "for line in lines[:10]:\n",
    "    print(line.strip())"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8ed51eb7-7f05-4452-83d1-a03ca1596f89",
   "metadata": {},
   "source": [
    "Another way to do the same thing is to use `read` to read the entire file into a string."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 61,
   "id": "3f51f0a9-7adf-4ee9-b8de-29e43e1b2ff1",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-08-31T18:38:48.406472Z",
     "iopub.status.busy": "2026-08-31T18:38:48.406385Z",
     "iopub.status.idle": "2026-08-31T18:38:48.408621Z",
     "shell.execute_reply": "2026-08-31T18:38:48.408425Z"
    },
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "1016511"
      ]
     },
     "execution_count": 61,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "string = words_path.read_text()\n",
    "len(string)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 62,
   "id": "c5460e74-2878-4d42-9816-6ee6ddde5adc",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-08-31T18:38:48.409758Z",
     "iopub.status.busy": "2026-08-31T18:38:48.409691Z",
     "iopub.status.idle": "2026-08-31T18:38:48.411409Z",
     "shell.execute_reply": "2026-08-31T18:38:48.411129Z"
    },
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'aa\\naah\\naahed\\naahing\\naahs\\naal\\naalii\\naaliis\\naals\\naardvark'"
      ]
     },
     "execution_count": 62,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "string[:55]"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "00941675-675b-4f5c-a0e0-19f13e98ca87",
   "metadata": {},
   "source": [
    "The result is a single string with more than a million characters.\n",
    "We can use the **`split`** method to split it into a list of words."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 63,
   "id": "fe7ea94e-5423-494e-aaf9-7efd4badc04c",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-08-31T18:38:48.412566Z",
     "iopub.status.busy": "2026-08-31T18:38:48.412496Z",
     "iopub.status.idle": "2026-08-31T18:38:48.417589Z",
     "shell.execute_reply": "2026-08-31T18:38:48.417357Z"
    },
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "113783"
      ]
     },
     "execution_count": 63,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "word_list = string.split()\n",
    "len(word_list)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "66123617-b280-42bb-a35a-54fdefad64f4",
   "metadata": {},
   "source": [
    "### Search\n",
    "\n",
    "Now, to check whether a string appears in the list, we can use the `in` operator.\n",
    "For example, `'demotic'` is in the list."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 64,
   "id": "ba57d1c8-4e5a-4ed5-b166-f0a6341fdb6e",
   "metadata": {
    "editable": true,
    "execution": {
     "iopub.execute_input": "2026-08-31T18:38:48.418790Z",
     "iopub.status.busy": "2026-08-31T18:38:48.418726Z",
     "iopub.status.idle": "2026-08-31T18:38:48.420705Z",
     "shell.execute_reply": "2026-08-31T18:38:48.420447Z"
    },
    "slideshow": {
     "slide_type": ""
    },
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 64,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "'demotic' in word_list"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4fee9d64-5fb5-4ee8-b66d-2a5b04fe80e1",
   "metadata": {
    "editable": true,
    "slideshow": {
     "slide_type": ""
    },
    "tags": []
   },
   "source": [
    "But `'contrafibularities'` is not."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 65,
   "id": "e267f533-c311-4e58-9706-8af86cf914c4",
   "metadata": {
    "editable": true,
    "execution": {
     "iopub.execute_input": "2026-08-31T18:38:48.421820Z",
     "iopub.status.busy": "2026-08-31T18:38:48.421760Z",
     "iopub.status.idle": "2026-08-31T18:38:48.424116Z",
     "shell.execute_reply": "2026-08-31T18:38:48.423900Z"
    },
    "slideshow": {
     "slide_type": ""
    },
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "False"
      ]
     },
     "execution_count": 65,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "'contrafibularities' in word_list"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 66,
   "id": "ch02-lists-word-search-exercise-q",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-08-31T18:38:48.425234Z",
     "iopub.status.busy": "2026-08-31T18:38:48.425175Z",
     "iopub.status.idle": "2026-08-31T18:38:48.427344Z",
     "shell.execute_reply": "2026-08-31T18:38:48.427146Z"
    },
    "tags": [
     "thebe-interactive"
    ]
   },
   "outputs": [],
   "source": [
    "### Exercise: Search a Word List\n",
    "# Use list membership and a loop to find requested words.\n",
    "# Print exactly:\n",
    "# apple: found\n",
    "# durian: missing\n",
    "# pear: found\n",
    "word_list = [\"apple\", \"banana\", \"pear\", \"plum\"]\n",
    "requested = [\"apple\", \"durian\", \"pear\"]\n",
    "### Your code starts here.\n",
    "\n",
    "\n",
    "\n",
    "### Your code ends here."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 67,
   "id": "ch02-lists-word-search-exercise-a",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-08-31T18:38:48.428548Z",
     "iopub.status.busy": "2026-08-31T18:38:48.428478Z",
     "iopub.status.idle": "2026-08-31T18:38:48.430083Z",
     "shell.execute_reply": "2026-08-31T18:38:48.429860Z"
    },
    "tags": [
     "hide-input"
    ]
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "apple: found\n",
      "durian: missing\n",
      "pear: found\n"
     ]
    }
   ],
   "source": [
    "### Solution\n",
    "word_list = [\"apple\", \"banana\", \"pear\", \"plum\"]\n",
    "requested = [\"apple\", \"durian\", \"pear\"]\n",
    "\n",
    "for word in requested:\n",
    "    if word in word_list:\n",
    "        status = \"found\"\n",
    "    else:\n",
    "        status = \"missing\"\n",
    "    print(f\"{word}: {status}\")"
   ]
  }
 ],
 "metadata": {
  "jupytext": {
   "default_lexer": "ipython3"
  },
  "kernelspec": {
   "display_name": ".venv",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.13.13"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
