{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 8. 여러 이터레이터에 대해 나란히 루프를 수행하려면 zip을 사용하라"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "리스트 컴프리헨션을 사용하면 소스 list에서 새로운 list를 파생시키기 쉽다."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[7, 4, 3]\n"
     ]
    }
   ],
   "source": [
    "names = ['Cecilia', '남궁민수', '어쩌고']\n",
    "counts = [len(n) for n in names]\n",
    "print(counts)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "두 리스트를 동시에 이터레이션할 경우 names 소스 리스트의 길이를 사용해 이터레이션할 수 있다."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "longest_name = None\n",
    "max_count = 0"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Cecilia\n"
     ]
    }
   ],
   "source": [
    "for i in range(len(names)):\n",
    "    count = counts[i]\n",
    "    if count > max_count:\n",
    "        longest_name = names[i]\n",
    "        max_count = count\n",
    "\n",
    "print(longest_name)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "어지럽다\n",
    "\n",
    "enumerate를 사용해보자"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "for i, name in enumerate(names):\n",
    "    count = counts[i]\n",
    "    if count > max_count:\n",
    "        longest_name = name\n",
    "        max_count = count"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "zip을 사용해보자\n",
    "\n",
    "zip은 둘 이상의 이터레이터를 지연 계산 제너레이터를 사용해 묶어준다."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "for name, count in zip(names, counts):\n",
    "    if count > max_count:\n",
    "        longest_name = name\n",
    "        max_count = count"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "zip은 자신이 감싼 이터레이터 중 어느 하나가 끝날때까지 튜플을 내놓는다."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "names.append('Rosalind')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Cecilia\n",
      "남궁민수\n",
      "어쩌고\n"
     ]
    }
   ],
   "source": [
    "for name, count in zip(names, counts):\n",
    "    print(name)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "zip에 전달한 리스트의 길이가 같지 않을 것으로 예상한다면 itertools 내장 모듈에 들어 있는 **zip_longest**를 대신 사용하는 것을 고려하라."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Cecilia: 7\n",
      "남궁민수: 4\n",
      "어쩌고: 3\n",
      "Rosalind: None\n"
     ]
    }
   ],
   "source": [
    "import itertools\n",
    "\n",
    "for name, count in itertools.zip_longest(names, counts):\n",
    "    print(f'{name}: {count}')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "zip_longest는 존재하지 않는 값을 자신에게 전달된 fillvalue로 대신한다. 디폴트는 None이다"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Cecilia: 7\n",
      "남궁민수: 4\n",
      "어쩌고: 3\n",
      "Rosalind: 1\n"
     ]
    }
   ],
   "source": [
    "for name, count in itertools.zip_longest(names, counts, fillvalue=1):\n",
    "    print(f'{name}: {count}')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 기억해야 할 내용\n",
    "- zip 내장 함수를 사용해 여러 이터레이터를 나란히 이터레이션할 수 있다.\n",
    "- zip은 튜플을 지연 계산하는 제너레이터를 만든다. 따라서 무한히 긴 입력에도 zip을 쓸 수 있다.\n",
    "- 입력 이터레이터의 길이가 서로 다르면 zip은 아무런 경고도 없이 가장 짧은 이터레이터 길이까지만 튜플을 내놓고 더 긴 이터레이터의 나머지 원소는 무시한다.\n",
    "- 가장 짧은 이터레이터에 맞춰 길이를 제한하지 않고 길이가 서로 다른 이터레이터에 대해 루프를 수행하려면 itertools 내장 모듈의 zip_longest 함수를 사용하라."
   ]
  }
 ],
 "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
}