{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "8ac27310-2b2a-4e32-ac6b-be69eb5eeb13",
   "metadata": {},
   "source": [
    "# List Operations\n",
    "\n",
    "This section covers how to work with lists using \n",
    "- operators, \n",
    "- built-in functions, and \n",
    "- methods."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "f6c5db9f",
   "metadata": {},
   "outputs": [],
   "source": [
    "import sys\n",
    "from pathlib import Path\n",
    "\n",
    "# Find project root by looking for _config.yml\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",
    "# Add project root to path\n",
    "sys.path.insert(0, str(project_root))\n",
    "\n",
    "# Import shared teaching helpers and cell magics\n",
    "from shared import thinkpython, diagram, jupyturtle, structshape\n",
    "from shared.download import download\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "25df7356",
   "metadata": {},
   "outputs": [],
   "source": [
    "fruits = ['apple', 'banana', 'cherry']\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "849630bb-837f-4825-8c34-71299d544c4a",
   "metadata": {},
   "source": [
    "## List Operators\n",
    "\n",
    "Python supports several operators that work directly with lists:"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8996fddb-3fcf-4b9e-ab72-dcf3862b6f3d",
   "metadata": {},
   "source": [
    "| Operator | Name | Description | Example | Result |\n",
    "|----------|------|-------------|---------|--------|\n",
    "| `+` | Concatenation | Combines two lists | `[1, 2] + [3, 4]` | `[1, 2, 3, 4]` |\n",
    "| `*` | Repetition | Repeats a list | `[1, 2] * 3` | `[1, 2, 1, 2, 1, 2]` |\n",
    "| **`in`** | **Membership** | Checks if item exists in list | `3 in [1, 2, 3]` | `True` |\n",
    "| `not in` | Non-membership | Checks if item doesn't exist | `5 not in [1, 2, 3]` | `True` |\n",
    "| `[]` | Indexing | Accesses element by position | `[10, 20, 30][0]` | `10` |\n",
    "| **`[:]`** | **Slicing** | Extracts portion of list | `[0, 1, 2, 3][1:3]` | `[1, 2]` |\n",
    "| **`==`** | **Equality** | Checks if lists are equal | `[1, 2] == [1, 2]` | `True` |\n",
    "| `!=` | Inequality | Checks if lists are not equal | `[1, 2] != [1, 3]` | `True` |\n",
    "| `<` | Less than | Lexicographic comparison | `[1, 2] < [1, 3]` | `True` |\n",
    "| `>` | Greater than | Lexicographic comparison | `[1, 3] > [1, 2]` | `True` |\n",
    "| `<=` | Less than or equal | Lexicographic comparison | `[1, 2] <= [1, 2]` | `True` |\n",
    "| `>=` | Greater than or equal | Lexicographic comparison | `[1, 3] >= [1, 2]` | `True` |"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1b057c0c",
   "metadata": {},
   "source": [
    "The `+` operator concatenates lists."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 46,
   "id": "66804de0",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[1, 2, 3, 4, 5, 6]"
      ]
     },
     "execution_count": 46,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "num1 = [1, 2, 3]\n",
    "num2 = [4, 5, 6]\n",
    "\n",
    "num1 + num2"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "474a5c40",
   "metadata": {},
   "source": [
    "The `*` operator repeats a list a given number of times."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 47,
   "id": "4a43e22a",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['spam', 'spam', 'spam', 'spam']"
      ]
     },
     "execution_count": 47,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "['spam'] * 4"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 48,
   "id": "484ebce4",
   "metadata": {
    "tags": [
     "thebe-interactive"
    ]
   },
   "outputs": [],
   "source": [
    "### EXERCISE: List Concatenation and Repetition\n",
    "# 1. Create two lists: list1 = [1, 2, 3] and list2 = [4, 5, 6]\n",
    "# 2. Concatenate them to create list3\n",
    "# 3. Create list4 by repeating [0] three times\n",
    "### Your code starts here:\n",
    "\n",
    "\n",
    "\n",
    "### Your code ends here."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 49,
   "id": "bf418a5d",
   "metadata": {
    "tags": [
     "hide-input"
    ]
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "List1 + List2: [1, 2, 3, 4, 5, 6]\n",
      "[0] * 3: [0, 0, 0]\n"
     ]
    }
   ],
   "source": [
    "# Solution\n",
    "list1 = [1, 2, 3]\n",
    "list2 = [4, 5, 6]\n",
    "list3 = list1 + list2\n",
    "list4 = [0] * 3\n",
    "\n",
    "print(f\"List1 + List2: {list3}\")\n",
    "print(f\"[0] * 3: {list4}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4bb45d01-6316-4d9a-86db-07fef9f46a85",
   "metadata": {},
   "source": [
    "### Membership Testing\n",
    "\n",
    "The `in` operator checks whether a given element appears anywhere in the list."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 50,
   "id": "c1c1ee1f",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 50,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "'apple' in fruits"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 51,
   "id": "da6c7318",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "False\n",
      "True\n"
     ]
    }
   ],
   "source": [
    "print('tomato' in fruits)\n",
    "print('tomato' not in fruits)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e81f7580-58d6-4629-b908-7b5e8a9d2eec",
   "metadata": {},
   "source": [
    "When checking membership with `in`, only top-level elements are considered. For example, `'spam'` is in nested `mixed_list`, but `10` is not (since it's inside a nested list):"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 52,
   "id": "a69319b0",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "True\n",
      "False\n"
     ]
    }
   ],
   "source": [
    "numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]\n",
    "mixed_list = ['spam', 2.0, 5, numbers ]\n",
    "\n",
    "print('spam' in mixed_list)     ### True\n",
    "print(10 in mixed_list)         ### False"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 53,
   "id": "34c6eb52",
   "metadata": {
    "tags": [
     "thebe-interactive"
    ]
   },
   "outputs": [],
   "source": [
    "### EXERCISE: Membership Testing\n",
    "inventory = ['apple', 'banana', 'orange', 'grape', 'mango']\n",
    "# 1. Check if 'orange' is in the inventory\n",
    "# 2. Check if 'strawberry' is NOT in the inventory\n",
    "# 3. Create a list of items to check: ['apple', 'kiwi', 'grape']\n",
    "#    and count how many of them are in inventory using a \n",
    "#    LIST COMPREHENSION and sum()\n",
    "### Your code starts here:\n",
    "\n",
    "\n",
    "\n",
    "### Your code ends here."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 54,
   "id": "0178ed80",
   "metadata": {
    "tags": [
     "hide-input"
    ]
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Has orange: True\n",
      "No strawberry: True\n",
      "Items found in inventory: 2\n"
     ]
    }
   ],
   "source": [
    "# Solution\n",
    "inventory = ['apple', 'banana', 'orange', 'grape', 'mango']\n",
    "has_orange = 'orange' in inventory\n",
    "no_strawberry = 'strawberry' not in inventory\n",
    "\n",
    "check_items = ['apple', 'kiwi', 'grape']\n",
    "count_found = sum( [item in inventory for item in check_items] ) \n",
    "### .count(True) is not needed because True is treated as 1 and False as 0 in sum()\n",
    "\n",
    "print(f\"Has orange: {has_orange}\")\n",
    "print(f\"No strawberry: {no_strawberry}\")\n",
    "print(f\"Items found in inventory: {count_found}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "96288b3b-09aa-48ef-8bfb-f0b3ae7d84aa",
   "metadata": {},
   "source": [
    "## List Methods/Functions"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8e1711a1-6d05-465b-a420-46a8df3d33b5",
   "metadata": {},
   "source": [
    "Python provides many built-in methods and functions that operate on lists. Common list methods and functions include:\n",
    "\n",
    "| Purpose | Function/Method | Description | Example | Result |\n",
    "|---------|-----------------|-------------|---------|--------|\n",
    "| **Creating/Copying** | `list()` | Creates a new list | `list(\"abc\")` | `['a', 'b', 'c']` |\n",
    "|  | `copy()` | Returns shallow copy | `[1, 2, 3].copy()` | `[1, 2, 3]` (new list) |\n",
    "| **Adding Items** | `append()` | Adds single item to end | `[1, 2].append(3)` | `[1, 2, 3]` |\n",
    "|  | `insert()` | Inserts item at position | `[1, 3].insert(1, 2)` | `[1, 2, 3]` |\n",
    "|  | `extend()` | Adds all items from iterable | `[1, 2].extend([3, 4])` | `[1, 2, 3, 4]` |\n",
    "| **Removing Items** | `remove()` | Removes first occurrence of value | `[1, 2, 3].remove(2)` | `[1, 3]` |\n",
    "|  | `pop()` | Removes and returns last item | `[1, 2, 3].pop()` | Returns `3`, list becomes `[1, 2]` |\n",
    "|  | `pop(index)` | Removes and returns item at index | `[1, 2, 3].pop(0)` | Returns `1`, list becomes `[2, 3]` |\n",
    "|  | `clear()` | Removes all items | `[1, 2, 3].clear()` | `[]` |\n",
    "| **Searching/Counting** | `index()` | Returns index of first occurrence | `[1, 2, 3].index(2)` | `1` |\n",
    "|  | `count()` | Counts occurrences of value | `[1, 2, 2, 3].count(2)` | `2` |\n",
    "| **Sorting/Reversing** | `sort()` | Sorts list in place | `[3, 1, 2].sort()` | `[1, 2, 3]` |\n",
    "|  | `sorted()` | Returns new sorted list | `sorted([3, 1, 2])` | `[1, 2, 3]` (original unchanged) |\n",
    "|  | `reverse()` | Reverses list in place | `[1, 2, 3].reverse()` | `[3, 2, 1]` |\n",
    "|  | `reversed()` | Returns reverse iterator | `list(reversed([1, 2, 3]))` | `[3, 2, 1]` |\n",
    "| **Information/Statistics** | `len()` | Returns number of items | `len([1, 2, 3])` | `3` |\n",
    "|  | `max()` | Returns largest item | `max([1, 2, 3])` | `3` |\n",
    "|  | `min()` | Returns smallest item | `min([1, 2, 3])` | `1` |\n",
    "|  | `sum()` | Returns sum of numeric items | `sum([1, 2, 3])` | `6` |\n",
    "\n",
    "Let's explore some of these with examples:"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "963f5b2b-f9b5-43b9-bc25-97f689c5ef99",
   "metadata": {},
   "source": [
    "### List Functions\n",
    "\n",
    "Python provides several built-in functions that work with lists to perform common operations, such as finding the length (`len()`), maximum (`max()`), minimum (`min()`), sum (`sum()`), sorting (`sorted()`), and type conversion (`list()`)."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "03cb7d4e-d19c-47e5-a96c-afff8b252003",
   "metadata": {},
   "source": [
    "The `len` function returns the **length** of a list as the count of number of the elements."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 55,
   "id": "eca29c8a",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "There are 5 numbers in [1, 2, 3, 4, 5].\n",
      "There are 5 fruits in ['apple', 'banana', 'cherry', 'date', 'elderberry'].\n"
     ]
    }
   ],
   "source": [
    "numbers = [1, 2, 3, 4, 5]\n",
    "fruits = ['apple', 'banana', 'cherry', 'date', 'elderberry']\n",
    "print(f\"There are {len(numbers)} numbers in {numbers}.\")\n",
    "print(f\"There are {len(fruits)} fruits in {fruits}.\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9cc84a14-09fc-4244-8f80-a57b92473f2a",
   "metadata": {},
   "source": [
    "The length of an empty list is `0`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 56,
   "id": "38541506",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "0"
      ]
     },
     "execution_count": 56,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "empty = []\n",
    "len(empty)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "fe756ee1-c51a-4086-b10f-2a10cc46a50d",
   "metadata": {},
   "source": [
    "No other mathematical operators work with lists, but the built-in function `sum` adds up the elements.\n",
    "And the `min` and `max` functions find the smallest and largest elements."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 57,
   "id": "96620f93",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "6\n",
      "1\n",
      "6\n"
     ]
    }
   ],
   "source": [
    "num1 = [1, 2, 3]\n",
    "num2 = [4, 5, 6]\n",
    "\n",
    "print(sum(num1))\n",
    "print(min(num1))\n",
    "print(max(num2))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a65d26fe-cb4d-4004-a635-2e5cda2d49ea",
   "metadata": {},
   "source": [
    "## List Modifying Methods\n",
    "\n",
    "Lists have built-in methods that allow you to modify them in place, such as adding, removing, or reordering elements."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 58,
   "id": "11a2ecd1",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Original list:\t\t ['a', 'b', 'c', 'd']\n",
      "After append 'e':\t ['a', 'b', 'c', 'd', 'e']\n",
      "After extend ['f', 'g']: ['a', 'b', 'c', 'd', 'e', 'f', 'g']\n",
      "After insert at 0:\t ['z', 'a', 'b', 'c', 'd', 'e', 'f', 'g']\n",
      "After remove 'z':\t ['a', 'b', 'c', 'd', 'e', 'f', 'g']\n",
      "Popped: g, Remaining:\t ['a', 'b', 'c', 'd', 'e', 'f']\n",
      "After clear:\t\t []\n"
     ]
    }
   ],
   "source": [
    "letters = ['a', 'b', 'c', 'd']\n",
    "print(f\"Original list:\\t\\t {letters}\")\n",
    "\n",
    "# append() - Adds element to the end\n",
    "letters.append('e')\n",
    "print(f\"After append 'e':\\t {letters}\")\n",
    "\n",
    "# extend() - Appends all elements from another list\n",
    "letters.extend(['f', 'g'])\n",
    "print(f\"After extend ['f', 'g']: {letters}\")\n",
    "\n",
    "# insert() - Inserts element at specific position\n",
    "letters.insert(0, 'z')\n",
    "print(f\"After insert at 0:\\t {letters}\")\n",
    "\n",
    "# remove() - Removes first occurrence of element\n",
    "letters.remove('z')\n",
    "print(f\"After remove 'z':\\t {letters}\")\n",
    "\n",
    "# pop() - Removes and returns element at index (or last if no index)\n",
    "last_item = letters.pop()\n",
    "print(f\"Popped: {last_item}, Remaining:\\t {letters}\")\n",
    "\n",
    "# clear() - Removes all elements\n",
    "temp = [1, 2, 3]\n",
    "temp.clear()\n",
    "print(f\"After clear:\\t\\t {temp}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "23a0f293",
   "metadata": {},
   "source": [
    "**Note:** If you try to `remove()` an element that doesn't exist, Python raises a `ValueError`. If you try to `pop()` from an empty list, Python raises an `IndexError`."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "cc1aac68-8337-4c2b-9771-7b7a82747295",
   "metadata": {},
   "source": [
    "## Iteration Helpers: `enumerate` and `zip`"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5501f012-d9c3-48f6-8e8c-9b0ca3c1d3dd",
   "metadata": {},
   "source": [
    "**Using `enumerate()`**\n",
    "\n",
    "When looping through a list, you sometimes need to know both the **element** and its **index**. The `enumerate()` function returns pairs of `(index, element)` for each item in the list."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 59,
   "id": "1f752a18",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0: apple\n",
      "1: banana\n",
      "2: cherry\n"
     ]
    }
   ],
   "source": [
    "fruits = ['apple', 'banana', 'cherry']\n",
    "\n",
    "for index, fruit in enumerate(fruits):\n",
    "    print(f\"{index}: {fruit}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c23beb37-37e3-41a6-8f13-74d6b82bf3ee",
   "metadata": {},
   "source": [
    "**Using `zip()`**\n",
    "\n",
    "The `zip()` function is useful when you need to loop through two or more lists in parallel. It pairs up elements from each list and returns tuples."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 60,
   "id": "7298f340",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Alice is 25 years old and lives in New York\n",
      "Bob is 30 years old and lives in London\n",
      "Charlie is 35 years old and lives in Tokyo\n"
     ]
    }
   ],
   "source": [
    "names = ['Alice', 'Bob', 'Charlie']\n",
    "ages = [25, 30, 35]\n",
    "cities = ['New York', 'London', 'Tokyo']\n",
    "\n",
    "for name, age, city in zip(names, ages, cities):\n",
    "    print(f\"{name} is {age} years old and lives in {city}\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 61,
   "id": "9cf32314",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<zip object at 0x110726cc0>\n",
      "[('Alice', 25, 'New York'), ('Bob', 30, 'London'), ('Charlie', 35, 'Tokyo')]\n",
      "{'Alice': 25, 'Bob': 30, 'Charlie': 35}\n"
     ]
    }
   ],
   "source": [
    "test = zip(names, ages, cities)\n",
    "print(test)         # This will print a zip object, not the contents\n",
    "print(list(test))   # Convert zip object to list to see contents\n",
    "\n",
    "test2  = zip(names, ages)\n",
    "print(dict(test2))  # Convert to dict to see contents (keys from names, values from ages)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "366d2980",
   "metadata": {
    "tags": [
     "thebe-interactive"
    ]
   },
   "outputs": [],
   "source": [
    "### EXERCISE: Using List Methods\n",
    "numbers = [3, 1, 4, 1, 5, 9, 2, 6]\n",
    "# 1. Count how many times 1 appears in the list \n",
    "# 2. Append the number 7 to the end\n",
    "# 3. Remove the first occurrence of 1\n",
    "# 4. Find the index of the number 5\n",
    "### Your code starts here:\n",
    "\n",
    "\n",
    "\n",
    "### Your code ends here."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 109,
   "id": "5501d681",
   "metadata": {
    "tags": [
     "hide-input"
    ]
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Count of 1s: 2\n",
      "List after appending 7: [3, 1, 4, 1, 5, 9, 2, 6, 7]\n",
      "List after removing first occurrence of 1: [3, 4, 1, 5, 9, 2, 6, 7]\n",
      "Index of 5: 3\n"
     ]
    }
   ],
   "source": [
    "# Solution\n",
    "numbers = [3, 1, 4, 1, 5, 9, 2, 6]\n",
    "count_ones = numbers.count(1)\n",
    "print(f\"Count of 1s: {count_ones}\")\n",
    "numbers.append(7)\n",
    "print(f\"List after appending 7: {numbers}\")\n",
    "numbers.remove(1)\n",
    "print(f\"List after removing first occurrence of 1: {numbers}\")\n",
    "index_of_five = numbers.index(5)\n",
    "print(f\"Index of 5: {index_of_five}\")\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 114,
   "id": "5ee315ec",
   "metadata": {
    "tags": [
     "thebe-interactive"
    ]
   },
   "outputs": [],
   "source": [
    "### EXERCISE: Using enumerate() and zip()\n",
    "### with the following lists:\n",
    "fruits = ['apple', 'banana', 'cherry']\n",
    "prices = [10, 20, 30]\n",
    "# 1. Use enumerate() to print the index and fruit name \n",
    "#    as \"0: apple\", \"1: banana\", etc.\n",
    "# 2. Use zip() to print each fruit with its corresponding price \n",
    "#    as \"apple costs 10\", \"banana costs 20\", etc.\n",
    "### Your code starts here:\n",
    "\n",
    "\n",
    "\n",
    "### Your code ends here."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "5c19497c",
   "metadata": {
    "tags": [
     "hide-input"
    ]
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0: apple\n",
      "1: banana\n",
      "2: cherry\n",
      "apple costs 10\n",
      "banana costs 20\n",
      "cherry costs 30\n"
     ]
    }
   ],
   "source": [
    "# Solution\n",
    "\n",
    "fruits = ['apple', 'banana', 'cherry']\n",
    "prices = [10, 20, 30]\n",
    "\n",
    "for index, fruit in enumerate(fruits):\n",
    "    print(f\"{index}: {fruit}\")      \n",
    "\n",
    "for fruit, price in zip(fruits, prices):\n",
    "    print(f\"{fruit} costs {price}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ae4bd6e9-f261-4908-a8fe-4e07b0ae31c5",
   "metadata": {},
   "source": [
    "## List Unpacking\n",
    "\n",
    "**Unpacking** is a Python feature that allows you to assign **multiple values** from a list (or any iterable) to **multiple variables** in a single statement. Instead of accessing elements one by one with indexing, you can extract them all at once."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "01a6b198",
   "metadata": {},
   "source": [
    "This makes your code more readable and **Pythonic**, especially when working with structured data."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e285933c",
   "metadata": {},
   "source": [
    "### Basic Unpacking"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 64,
   "id": "7b199cc7-36e2-4082-9aa5-19d1136168cb",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Without unpacking (verbose)\n",
    "point = [10, 20, 30]\n",
    "x = point[0]\n",
    "y = point[1]\n",
    "z = point[2]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 65,
   "id": "abc07bbe-0852-4bef-b1d8-8d674f00c837",
   "metadata": {},
   "outputs": [],
   "source": [
    "# With unpacking (concise)\n",
    "point = [10, 20, 30]\n",
    "x, y, z = point         ### assigns 10 to x, 20 to y, 30 to z"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 66,
   "id": "e6e89e67",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "first=h, second=i\n"
     ]
    }
   ],
   "source": [
    "# Unpacking actually works with any iterable\n",
    "\n",
    "first, second = \"hi\"\n",
    "print(f\"first={first}, second={second}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3754c88d",
   "metadata": {},
   "source": [
    "### With Star Operator\n",
    "\n",
    "- Using `*` (the **unpacking operator**) allows you to capture multiple elements.\n",
    "- You can only have one `*variable` per unpacking statement."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 67,
   "id": "664bf954",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "First: 1\n",
      "Rest: [2, 3, 4, 5]\n"
     ]
    }
   ],
   "source": [
    "# Capture the first element and the rest\n",
    "numbers = [1, 2, 3, 4, 5]\n",
    "first, *rest = numbers\n",
    "\n",
    "print(f\"First: {first}\")\n",
    "print(f\"Rest: {rest}\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 68,
   "id": "458191e0",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "First: 1, Middle: [2, 3, 4], Last: 5\n"
     ]
    }
   ],
   "source": [
    "# Capture first, last, and middle\n",
    "first, *middle, last = numbers\n",
    "print(f\"First: {first}, Middle: {middle}, Last: {last}\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 69,
   "id": "c918f47c",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Most: [1, 2, 3, 4], Last: 5\n"
     ]
    }
   ],
   "source": [
    "# Capture last element\n",
    "*most, last = numbers\n",
    "print(f\"Most: {most}, Last: {last}\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 70,
   "id": "a35aaa3a",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "First: P\n",
      "Middle: ['y', 't', 'h', 'o']\n",
      "Last: n\n"
     ]
    }
   ],
   "source": [
    "### Unpacking works with all iterables, including \n",
    "### a string into individual characters\n",
    "\n",
    "word = \"Python\"\n",
    "first, *middle, last = word\n",
    "\n",
    "print(f\"First: {first}\")\n",
    "print(f\"Middle: {middle}\")\n",
    "print(f\"Last: {last}\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "aa16de5a",
   "metadata": {},
   "source": [
    "### Unpacking in Function Calls\n",
    "\n",
    "The `*` operator can also unpack a list into function **arguments**:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 71,
   "id": "23d5fe56",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Alice is 30 years old and lives in New York\n"
     ]
    }
   ],
   "source": [
    "# Unpack a list as function arguments\n",
    "def display_info(name, age, city):\n",
    "    print(f\"{name} is {age} years old and lives in {city}\")\n",
    "\n",
    "person = ['Alice', 30, 'New York']\n",
    "display_info(*person)  ### unpacks to display_info('Alice', 30, 'New York')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 72,
   "id": "76cd75e3",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1 2 3 4 5\n",
      "1-2-3-4-5\n"
     ]
    }
   ],
   "source": [
    "# Useful with functions like print\n",
    "values = [1, 2, 3, 4, 5]\n",
    "print(*values)              # Prints: 1 2 3 4 5 (separated by spaces)\n",
    "print(*values, sep='-')     # Prints: 1-2-3-4-5"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a3387bdb",
   "metadata": {},
   "source": [
    "**Common use cases:**\n",
    "- Swapping values: `a, b = b, a`\n",
    "- Parsing CSV data: `name, age, email = row.split(',')`\n",
    "- Function returns: `min_val, max_val = find_min_max(numbers)`\n",
    "- Ignoring values: `first, *_, last = data` (use `_` for values you don't need)\n",
    "\n",
    "Note: \n",
    "- `_` in `*_` is used as a **throwaway variable name**, it's a Python convention meaning \"I don't care about this value.\""
   ]
  }
 ],
 "metadata": {
  "celltoolbar": "Tags",
  "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.7"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
