{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<p style=\"text-align:center\">\n",
    "    <a href=\"https://nbviewer.jupyter.org/github/twMr7/Python-Machine-Learning/blob/master/06-Tuple_Operations.ipynb\">\n",
    "        Open In Jupyter nbviewer\n",
    "        <img style=\"float: center;\" src=\"https://nbviewer.jupyter.org/static/img/nav_logo.svg\" width=\"120\" />\n",
    "    </a>\n",
    "</p>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/twMr7/Python-Machine-Learning/blob/master/06-Tuple_Operations.ipynb)\n",
    "\n",
    "# 6. `tuple` 序列容器操作\n",
    "\n",
    "`tuple` 也是存放序列性資料的結構。語法使用逗號 `,` 分隔資料元素,用小括號(parentheses)`(` `)` 成對包住所有元素,但括號可以省略。 `tuple` 可以是巢狀多維度的,同一個 `tuple` 中也可以存放異質類型資料,通常使用在函式參數的傳遞與回傳。\n",
    "\n",
    "元素內容是按照儲存順序的 index 存取,語法為 **`[ index ]`**。 如果按照由前往後的順序,**第一個元素 index 是0**,依次往後遞增; 如果反過來由後往前存取,**最後一個元素 index 可以用-1**,依次向前遞減。\n",
    "\n",
    "| Tuple 範例                         | 說明                                          |\n",
    "|------------------------------------|-----------------------------------------------|\n",
    "| `()`                               | 空的 tuple                                    |\n",
    "| `('code',)`                        | 單一元素的 tuple                              |\n",
    "| `(5, 6, 7, 8)`                     | 四個數字元素的 tuple                          |\n",
    "| `('code', (42, 3.1415), 1.23, {})` | 巢狀、異質的 tuple                            |\n",
    "| `'code', 42, 3.1415, 1.23`         | 括號可以省略                                  |\n",
    "\n",
    "- 內建函式 `tuple()` 可以用來建構一個新的tuple。\n",
    "- 內建函式 `len()` 可以用來回傳容器裡的元素個數。\n",
    "- 內建函式 `min()` 可以用來回傳容器中最小的元素。\n",
    "- 內建函式 `max()` 可以用來回傳容器中最大的元素。\n",
    "\n",
    "`tuple` 在建立後,元素內容**不可以**就地變更(immutable)。 `tuple` 是序列容器,所以一般 immutable 序列容器的共同方法都可以用,參閱官方文件 [Common Sequence Operations](https://docs.python.org/3/library/stdtypes.html#common-sequence-operations)。\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### § `tuple` 是不能 In-Place 就地變更的序列容器。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "T = (123, '345', (5, 67), 7.89).\n"
     ]
    }
   ],
   "source": [
    "T = 123, '345', (5, 67), 7.89\n",
    "print('T = {}.'.format(T))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "the last element is 7.89\n"
     ]
    }
   ],
   "source": [
    "# 可以用索引讀取,但想要變更元素值一定會出現 TypeError\n",
    "#T[-1] = 987\n",
    "print('the last element is {}'.format(T[-1]))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "T = ([123], ['345'], [5, 67], [7.89]).\n"
     ]
    }
   ],
   "source": [
    "# 但 tuple 裡面可以放 mutable 的物件\n",
    "T = [123], ['345'], [5, 67], [7.89]\n",
    "print('T = {}.'.format(T))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "the last element is now [987]\n"
     ]
    }
   ],
   "source": [
    "# tuple 裡的 mutable 物件內容當然可以 in-place 修改\n",
    "T[-1][0] = 987\n",
    "print('the last element is now {}'.format(T[-1]))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### § 一般序列容器的串接、重複複製、和 slicing 都可以用"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "T = ([123], ['345'], [5, 67], [987], [6, 54], ['32']).\n"
     ]
    }
   ],
   "source": [
    "# 串接\n",
    "T += [6, 54], ['32']\n",
    "print('T = {}.'.format(T))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "T = ([123], ['345'], [5, 67], [123], ['345'], [5, 67], [123], ['345'], [5, 67]).\n"
     ]
    }
   ],
   "source": [
    "# 重複複製\n",
    "T = T[:3] * 3\n",
    "print('T = {}.'.format(T))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "ename": "TypeError",
     "evalue": "'tuple' object does not support item assignment",
     "output_type": "error",
     "traceback": [
      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[1;31mTypeError\u001b[0m                                 Traceback (most recent call last)",
      "\u001b[1;32m<ipython-input-7-12b6efc4295e>\u001b[0m in \u001b[0;36m<module>\u001b[1;34m\u001b[0m\n\u001b[0;32m      1\u001b[0m \u001b[1;31m# tuple 的成員不能 in-place 修改,\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 2\u001b[1;33m \u001b[0mT\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;36m2\u001b[0m\u001b[1;33m]\u001b[0m \u001b[1;33m=\u001b[0m \u001b[1;34m'X'\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m",
      "\u001b[1;31mTypeError\u001b[0m: 'tuple' object does not support item assignment"
     ]
    }
   ],
   "source": [
    "# tuple 的成員不能 in-place 修改,\n",
    "T[2] = 'X'"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "T = ([123], ['345'], ['X', 67], [123], ['345'], ['X', 67], [123], ['345'], ['X', 67]).\n"
     ]
    }
   ],
   "source": [
    "# 但元素是 mutable 的其元素可以 in-place 修改\n",
    "T[2][0] = 'X'\n",
    "print('T = {}.'.format(T))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "T = (['345'], ['X', 67], [123]).\n"
     ]
    }
   ],
   "source": [
    "# slicing 指定從原本的片段中產生新的 list 物件\n",
    "T = T[1:4]\n",
    "print('T = {}.'.format(T))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### § 序列容器的元素卸載 (unpacking)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "a = ['345'], b = ['X', 67], c = [123].\n"
     ]
    }
   ],
   "source": [
    "# 卸載常見於函式的回傳值\n",
    "a, b, c = T\n",
    "print('a = {}, b = {}, c = {}.'.format(a, b, c))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### § 為甚麼要有 `tuple` 這樣的容器\n",
    "有 `list` 這麼方便好用的容器了,為甚麼還需要 `tuple` 這種限制多、操作方法少的容器?\n",
    "- `tuple` 不能就地變更 (immutability) 的特性,對於維護程式中資料的完整性 (integrity) 是有幫助的。\n",
    "- Immutability 及 integrity 是維持物件關聯性記錄的重要特性,也就是這樣的特性,`dict` 容器的 key 可以是 `tuple` 但不能用 `list`。"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "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.8.8"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}