{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "737e79eb",
   "metadata": {},
   "source": [
    "# Dictionaries"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "200584f6",
   "metadata": {
    "tags": [
     "hide-input"
    ]
   },
   "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\n",
    "from shared.download import download\n",
    "\n",
    "# Register as top-level modules so direct imports work in subsequent cells\n",
    "sys.modules['thinkpython'] = thinkpython\n",
    "sys.modules['diagram'] = diagram\n",
    "sys.modules['jupyturtle'] = jupyturtle\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9963a57e",
   "metadata": {},
   "source": [
    "This chapter presents a built-in type called a dictionary.\n",
    "\n",
    "It is one of Python's best features -- and the building block of many efficient and elegant algorithms.\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "be7467bb",
   "metadata": {},
   "source": [
    "## What Is a Dictionary?\n",
    "\n",
    "A dictionary in Python is a built-in data type used to store data in key–value pairs. A Python dictionary is like a real world dictionary, where you look up a word for its definition. In Python dictionary, you look up a **key** for the **value**. \n",
    "\n",
    "The key characteristics of a dictionary are:\n",
    "\n",
    "1. Dictionaries are **mutable** (can be changed)\n",
    "2. Keys must be **immutable** (strings, numbers, tuples)\n",
    "3. A dictionary represents a **mapping** from **keys** to **values**. \n",
    "4. **Keys** must be **unique**\n",
    "5. **Values** can be any data type\n",
    "\n",
    "In terms formatting, \n",
    "- Each dictionary item consists of a **key** and a **value** separated by a **colon**. \n",
    "- Dictionary items are separated by **commas** and enclosed in **curly braces**."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3a94f8ae",
   "metadata": {},
   "source": [
    "A **dictionary** is like a list, but more general. In a list, the indices have to be integers; in a dictionary they can be (almost) any type.\n",
    "\n",
    "| Feature   | List             | Dictionary        |\n",
    "| --------- | ---------------- | ----------------- |\n",
    "| Access by | Index (0,1,2)    | Key               |\n",
    "| Structure | Ordered sequence | Key-value mapping |\n",
    "| Best for  | Ordered data     | Labeled data      |\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "bb0fdc15",
   "metadata": {},
   "source": [
    "As seen in the example below: \n",
    "\n",
    "- A **list** of number words can be accessed using an integer as an **index**. \n",
    "- A **dictionary** goes in the other direction, and look up a word to get the corresponding integer; in other words, using the keys to look up the values."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "20dd9f32",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "['zero', 'one', 'two']\n",
      "one\n",
      "{'zero': 0, 'one': 1, 'two': 2}\n",
      "1\n"
     ]
    }
   ],
   "source": [
    "nums_lst = ['zero', 'one', 'two']\n",
    "print(nums_lst)\n",
    "print(nums_lst[1])\n",
    "\n",
    "nums_dic = {'zero': 0, 'one': 1, 'two': 2}\n",
    "print(nums_dic)\n",
    "print(nums_dic['one'])"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2c2f6f79",
   "metadata": {},
   "source": [
    "In mathematical language, a dictionary represents a **mapping** from keys to values, so you can also say that each key \"maps to\" a value.\n",
    "In this example, each number word maps to the corresponding integer.\n",
    "\n",
    "The following figure shows the state diagram for `numbers`.\n",
    "A dictionary is represented by a box with the word \"dict\" outside and the items inside.\n",
    "Each item is represented by a key and an arrow pointing to a value.\n",
    "The quotation marks indicate that the keys here are strings, not variable names."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "e9004edf",
   "metadata": {
    "tags": [
     "remove-input"
    ]
   },
   "outputs": [],
   "source": [
    "from shared.diagram import make_dict, Binding, Value\n",
    "\n",
    "numbers = {'zero': 0, 'one': 1, 'two': 2}\n",
    "\n",
    "d1 = make_dict(numbers, dy=-0.3, offsetx=0.37)\n",
    "binding1 = Binding(Value('numbers'), d1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "3b05ed1f",
   "metadata": {
    "tags": [
     "remove-input"
    ]
   },
   "outputs": [
    {
     "data": {
      "image/png": "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",
      "text/plain": [
       "<Figure size 183x124 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "from shared.diagram import diagram, adjust, Bbox\n",
    "\n",
    "width, height, x, y = [1.83, 1.24, 0.49, 0.85]\n",
    "ax = diagram(width, height)\n",
    "bbox = binding1.draw(ax, x, y)\n",
    "# adjust(x, y, bbox)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "fc778385",
   "metadata": {},
   "source": [
    "## When to Use a Dictionary\n",
    "\n",
    "You use a dictionary when:\n",
    "- You need labeled data\n",
    "- You want fast lookups by name\n",
    "- You need a mapping relationship\n",
    "\n",
    "Examples of dictionaries:\n",
    "\n",
    "- Student records\n",
    "- **Configuration** settings\n",
    "- Word counts\n",
    "- **JSON** data"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6ef15bbc",
   "metadata": {},
   "source": [
    "## Creating Dictionaries\n",
    "\n",
    "Python provides several ways to create a dictionary, depending on whether you already have the data or are building it incrementally. T \n",
    "\n",
    "1. **dict literal**: the most common approach to create a dictionary\n",
    "2. `dict()` constructor: to turn sequences into dictionaries\n",
    "3. dictionary comprehensions: are useful when keys and values come from other sources"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "657c28ae",
   "metadata": {},
   "source": [
    "Python also has a `dict.fromkeys()` method, which is a special case in creating dictionaries. Overall, common ways ways to create a dictionary include:\n",
    "\n",
    "| # | Method | Syntax | Notes |\n",
    "|---|---|---|---|\n",
    "| 1 | Empty dict literal | `{}` | Fastest way to create an empty dict |\n",
    "| 2 | Dict literal | `{'a': 1, 'b': 2}` | Keys and values known up front |\n",
    "| 3 | `dict()` constructor | `dict(a=1, b=2)` | Keys must be valid identifiers |\n",
    "| 4 | From list of tuples | `dict([('a', 1), ('b', 2)])` | Useful when pairs are already in a sequence |\n",
    "| 5 | `dict.fromkeys()` | `dict.fromkeys(['a', 'b'], 0)` | All keys share the same default value |\n",
    "| 6 | Dict comprehension | `{k: v for k, v in items}` | Build from any iterable with an expression |"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9e3f77f0",
   "metadata": {},
   "source": [
    "Pay attention to ways 2, 3, and 4. We usually use dict literal for creating dictionaries but you should know how to use the `dict()` constructor to turn a sequence into a dictionary. Also, try to transfer your skill in list comprehension and tuple comprehension to dictionary comprehension. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "fe26184b",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Empty literal:        {}\n",
      "Dict literal:         {'zero': 0, 'one': 1, 'two': 2}\n",
      "dict() keywords:      {'zero': 0, 'one': 1, 'two': 2}\n",
      "dict() from tuples:   {'zero': 0, 'one': 1, 'two': 2}\n",
      "dict.fromkeys():      {'zero': 0, 'one': 0, 'two': 0}\n",
      "Dict comprehension:   {'zero': 0, 'one': 1, 'two': 2}\n"
     ]
    }
   ],
   "source": [
    "# 1. Empty dict literal\n",
    "d1 = {}\n",
    "\n",
    "# 2. Dict literal with items\n",
    "d2 = {'zero': 0, 'one': 1, 'two': 2}\n",
    "\n",
    "# 3. dict() constructor with keyword arguments (keys must be valid identifiers)\n",
    "d3 = dict(zero=0, one=1, two=2)\n",
    "\n",
    "# 4. dict() from a list of (key, value) tuples\n",
    "d4 = dict([('zero', 0), ('one', 1), ('two', 2)])\n",
    "\n",
    "# 5. dict.fromkeys() — all keys share the same default value\n",
    "d5 = dict.fromkeys(['zero', 'one', 'two'], 0)\n",
    "\n",
    "# 6. Dict comprehension\n",
    "words = ['zero', 'one', 'two']\n",
    "d6 = {word: idx for idx, word in enumerate(words)} # note the two variables\n",
    "\n",
    "print(\"Empty literal:       \", d1)\n",
    "print(\"Dict literal:        \", d2)\n",
    "print(\"dict() keywords:     \", d3)\n",
    "print(\"dict() from tuples:  \", d4)\n",
    "print(\"dict.fromkeys():     \", d5)\n",
    "print(\"Dict comprehension:  \", d6)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e5909815",
   "metadata": {},
   "source": [
    "To give some details about dictionary creation, let's use the dictionary literal to create a dictionary, which is to put the items inside curly braces. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "d73e8aab",
   "metadata": {},
   "outputs": [],
   "source": [
    "numbers = {'zero': 0, 'one': 1, 'two': 2}"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b79066d8",
   "metadata": {},
   "source": [
    "Each item consists of a **key** and a **value** separated by a **colon**.\n",
    "The items are separated by commas and enclosed in curly braces.\n",
    "\n",
    "Another way to create a dictionary is to use the `dict` function.\n",
    "We can make an empty dictionary like this."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "f597dc41",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{}"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "empty = dict()\n",
    "empty"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "991fb3e2",
   "metadata": {},
   "source": [
    "Or, if you have a list like [ \"zero\", \"one\", \"two\"], you can use `enumerate()` to create a dictionary."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "888528e3",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{'zero': 0, 'one': 1, 'two ': 2}\n"
     ]
    }
   ],
   "source": [
    "lst = [\"zero\", \"one\", \"two \"]\n",
    "\n",
    "dict_words = {}\n",
    "for idx, word in enumerate(lst):\n",
    "    dict_words[word] = idx\n",
    "\n",
    "print(dict_words)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d5cbea30",
   "metadata": {},
   "source": [
    "And we can make a copy of a dictionary like this."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "88f7eab1",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'zero': 0, 'one': 1, 'two': 2}"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "numbers_copy = dict(numbers)\n",
    "numbers_copy"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "959ce6d9",
   "metadata": {},
   "source": [
    "It is often useful to make a copy before performing operations that modify dictionaries."
   ]
  }
 ],
 "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
}
