{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 36. 이터레이터나 제너레이터를 다룰 때는 itertools를 사용하라"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import itertools"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 여러 이터레이터 연결하기"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[1, 2, 3, 4, 5, 6]\n"
     ]
    }
   ],
   "source": [
    "# chain\n",
    "\n",
    "it = itertools.chain([1, 2, 3], [4, 5, 6])\n",
    "print(list(it))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "['안녕', '안녕', '안녕']\n"
     ]
    }
   ],
   "source": [
    "# repeat\n",
    "\n",
    "it = itertools.repeat('안녕', 3)\n",
    "print(list(it))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[1, 2, 1, 2, 1, 2, 1, 2, 1, 2]\n"
     ]
    }
   ],
   "source": [
    "# cycle\n",
    "\n",
    "it = itertools.cycle([1, 2])\n",
    "result = [next(it) for _ in range(10)]\n",
    "print(result)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "['하나', '둘']\n",
      "['하나', '둘']\n",
      "['하나', '둘']\n"
     ]
    }
   ],
   "source": [
    "# tee\n",
    "\n",
    "it1, it2, it3 = it = itertools.tee(['하나', '둘'], 3)\n",
    "print(list(it1))\n",
    "print(list(it2))\n",
    "print(list(it3))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "zip: [('하나', 1), ('둘', 2)]\n",
      "zip_longest: [('하나', 1), ('둘', 2), ('셋', '없음')]\n"
     ]
    }
   ],
   "source": [
    "# zip_longest\n",
    "\n",
    "keys = ['하나', '둘', '셋']\n",
    "values = [1, 2]\n",
    "\n",
    "normal = list(zip(keys, values))\n",
    "print('zip:', normal)\n",
    "\n",
    "it = it = itertools.zip_longest(keys, values, fillvalue='없음')\n",
    "longest = list(it)\n",
    "print('zip_longest:', longest)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 이터레이터에서 원소 거르기"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "앞에서 다섯개: [1, 2, 3, 4, 5]\n",
      "중간의 홀수들 [3, 5, 7]\n"
     ]
    }
   ],
   "source": [
    "# isslice\n",
    "\n",
    "values = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]\n",
    "\n",
    "first_five = itertools.islice(values, 5)\n",
    "print('앞에서 다섯개:', list(first_five))\n",
    "\n",
    "middle_odds = itertools.islice(values, 2, 8, 2)\n",
    "print('중간의 홀수들', list(middle_odds))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[1, 2, 3, 4, 5, 6]\n"
     ]
    }
   ],
   "source": [
    "# takewhile\n",
    "\n",
    "values = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]\n",
    "less_then_seven = lambda x: x < 7\n",
    "it = it = itertools.takewhile(less_then_seven, values)\n",
    "print(list(it))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[7, 8, 9, 10]\n"
     ]
    }
   ],
   "source": [
    "# dropwhile\n",
    "\n",
    "values = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]\n",
    "less_then_seven = lambda x: x < 7\n",
    "it = itertools.dropwhile(less_then_seven, values)\n",
    "print(list(it))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "filter: [2, 4, 6, 8, 10]\n",
      "filter false: [1, 3, 5, 7, 9]\n"
     ]
    }
   ],
   "source": [
    "# filterfalse\n",
    "\n",
    "values = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]\n",
    "evens = lambda x: x % 2 == 0\n",
    "filter_result = filter(evens, values)\n",
    "print('filter:', list(filter_result))\n",
    "\n",
    "filter_false_result = itertools.filterfalse(evens, values)\n",
    "print('filter false:', list(filter_false_result))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 이터레이터에서 원소의 조합 만들어내기"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "합계: [1, 3, 6, 10, 15, 21, 28, 36, 45, 55]\n",
      "20으로 나눈 나머지의 합계: [1, 3, 6, 10, 15, 1, 8, 16, 5, 15]\n"
     ]
    }
   ],
   "source": [
    "# accumulate\n",
    "\n",
    "values = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]\n",
    "sum_reduce = itertools.accumulate(values)\n",
    "print('합계:', list(sum_reduce))\n",
    "\n",
    "def sum_modulo_20(first, second):\n",
    "    output = first + second\n",
    "    return output % 20\n",
    "\n",
    "modulo_reduce = itertools.accumulate(values, sum_modulo_20)\n",
    "print('20으로 나눈 나머지의 합계:', list(modulo_reduce))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "리스트 한 개: [(1, 1), (1, 2), (2, 1), (2, 2)]\n",
      "리스트 두 개: [(1, 'a'), (1, 'b'), (2, 'a'), (2, 'b')]\n"
     ]
    }
   ],
   "source": [
    "# product\n",
    "\n",
    "single = itertools.product([1, 2], repeat=2)\n",
    "print('리스트 한 개:', list(single))\n",
    "\n",
    "multiple = itertools.product([1, 2], ['a', 'b'])\n",
    "print('리스트 두 개:', list(multiple))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[(1, 2), (1, 3), (1, 4), (2, 1), (2, 3), (2, 4), (3, 1), (3, 2), (3, 4), (4, 1), (4, 2), (4, 3)]\n"
     ]
    }
   ],
   "source": [
    "# permutations\n",
    "\n",
    "it = itertools.permutations([1, 2, 3, 4], 2)\n",
    "print(list(it))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[(1, 2), (1, 3), (1, 4), (2, 3), (2, 4), (3, 4)]\n"
     ]
    }
   ],
   "source": [
    "# combinations\n",
    "\n",
    "it = itertools.combinations([1, 2, 3, 4], 2)\n",
    "print(list(it))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[(1, 1), (1, 2), (1, 3), (1, 4), (2, 2), (2, 3), (2, 4), (3, 3), (3, 4), (4, 4)]\n"
     ]
    }
   ],
   "source": [
    "# combinations_with_replacement\n",
    "\n",
    "it = itertools.combinations_with_replacement([1, 2, 3, 4], 2)\n",
    "print(list(it))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 기억해야 할 내용\n",
    "- 이터레이터나 제너레이터를 다루는 itertools 함수는 세 가지 범주로 나눌 수 있다.\n",
    "    - 여러 이터레이터를 연결함\n",
    "    - 이터레이터의 원소를 걸러냄\n",
    "    - 원소의 조합을 만들어냄\n",
    "- 파이썬 인터프리터에서 help(itertools)를 입력한 후 표시되는 문서를 살펴보면 더 많은 고급 함수와 추가 파라미터를 알 수 있으며, 이를 사용하는 유용한 방법도 확인할 수 있다."
   ]
  }
 ],
 "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.2"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}