{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Condicionales y bucles\n",
    "\n",
    "El momento en que Python deja de ser una calculadora, y la sangría que no es estética sino sintaxis.\n",
    "\n",
    "Cuaderno de práctica del capítulo 5 de **Python desde cero**, de Miss Yera.\n",
    "\n",
    "Corre de arriba abajo. Si lo abres en Google Colab no necesitas instalar nada.\n",
    "\n",
    "Capítulo completo: https://missyera.com/guias/python-desde-cero/control-de-flujo/\n",
    "\n",
    "Los ejercicios están al final y traen una celda vacía debajo de cada uno. Las\n",
    "respuestas viven en el cuaderno de soluciones, y merece la pena pelearse un\n",
    "rato antes de abrirlo 💛"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Antes de empezar\n",
    "\n",
    "Esta celda baja el ayudante que corrige tus ejercicios. Después, en cada\n",
    "ejercicio que se pueda corregir solo, vas a ver `%%revisa` arriba de la celda:\n",
    "escribe tu respuesta debajo, ejecuta, y te digo si te salió 💛"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import urllib.request\n",
    "\n",
    "# El ayudante de los cuadernos. Trae la corrección de los ejercicios y, en los\n",
    "# capítulos de consola, la celda mágica que ejecuta los comandos. Se baja en\n",
    "# vez de venir pegado aquí para que siempre sea el último.\n",
    "urllib.request.urlretrieve(\n",
    "    \"https://missyera.com/static/cuadernos/revisa.py\", \"revisa.py\")\n",
    "import revisa\n",
    "revisa.carga({\n",
    "    1: \"QmFqbw==\",\n",
    "    2: \"VG90YWwgUy8xLDM1MC41MCwgMiBkZXNjYXJ0YWRvcw==\",\n",
    "    3: \"IDEuIExpbWEKIDIuIEFyZXF1aXBhCiAzLiBDdXNjbwogNC4gUGl1cmE=\",\n",
    "    4: \"QmViaWRhczogcXVlZGFuIDEyCkxpbXBpZXphOiBxdWVkYW4gOA==\",\n",
    "    5: \"MTkgbWVzZXMsIHRlcm1pbmFzIGNvbiBTLzIwLDIwMA==\",\n",
    "    6: \"T0sgQzAwNDUKT0sgQzAzMjUKQ8OzZGlnbyB2YWPDrW8gZW4gbGEgcG9zaWNpw7NuIDI=\",\n",
    "    7: \"MzAw\",\n",
    "    8: \"Mg==\",\n",
    "    9: \"Q2xpZW50ZSBzYXRpc2ZlY2hv\",\n",
    "    10: \"TWVzIDE6IHF1ZWRhbiBTLzIzMDAKTWVzIDI6IHF1ZWRhbiBTLzE2MDAKTWVzIDM6IHF1ZWRhbiBTLzkwMApNZXMgNDogcXVlZGFuIFMvMjAwCk1lcyA1OiBxdWVkYW4gUy8tNTAw\",\n",
    "    11: \"aGF5IGFsZ3VuIG1vbnRvIG5lZ2F0aXZvIDogVHJ1ZQp0b2RhcyB0aWVuZW4gdW5pZGFkZXMgICAgOiBGYWxzZQpjdWFudGFzIHBhc2FuIGRlIG1pbCAgICAgOiAxCmhheSBhbGd1bmEgZGUgVHJ1amlsbG8gICA6IEZhbHNl\",\n",
    "    12: \"QzAyNjA6IFMvMjQ4MC44NCBlbiBDdXNjbwpDMDk5OTogbm8gZXN0YSBlbiBsYXMgNCB2ZW50YXM=\",\n",
    "    13: \"QXJlcXVpcGEgICAtPiBzdXIKTGltYSAgICAgICAtPiBjZW50cm8KQ3VzY28gICAgICAtPiBzdXIKUGl1cmEgICAgICAtPiBub3J0ZQ==\",\n",
    "    14: \"Ym9ycmFuZG8gc29icmUgbGEgbWFyY2hhOiBbMTIwLjAsIDM0MC41LCAtOC4wLCA4OTAuMF0KY29uIHVuYSBsaXN0YSBudWV2YSAgICAgOiBbMTIwLjAsIDM0MC41LCA4OTAuMF0KY3VhbnRvcyBuZWdhdGl2b3MgaGFiaWEgOiAz\",\n",
    "}, lenguaje=\"python\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Hola! Aquí empieza a ser un programa"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Hasta ahora Python era una calculadora con memoria. Guardaba valores y hacía\n",
    "cuentas 🧮\n",
    "\n",
    "Con este capítulo empieza a **tomar decisiones** y a\n",
    "**repetir trabajo**, que son las dos cosas por las que valió la pena\n",
    "aprenderlo."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## La sangría, que aquí es sintaxis"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Antes de nada, esto, porque es lo que más frustra la primera semana.\n",
    "\n",
    "En otros lenguajes los bloques se marcan con llaves y la sangría es decoración.\n",
    "En Python **la sangría es la que dice qué está dentro y qué está\n",
    "fuera**. No es estética, es gramática."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "monto = 1500\n",
    "\n",
    "if monto > 1000:\n",
    "    print('Venta grande')\n",
    "    print('Se avisa al supervisor')\n",
    "print('Esto sale siempre')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Los dos primeros `print` están dentro del `if` porque\n",
    "tienen cuatro espacios. El tercero está fuera porque no los tiene. Cambia la\n",
    "sangría y cambias el programa.\n",
    "\n",
    "Las reglas que te evitan el 99% de los problemas:\n",
    "\n",
    "- 📏 Cuatro espacios. Siempre cuatro, nunca dos ni ocho. Lo dice PEP 8 y lo\n",
    "respeta todo el mundo.\n",
    "\n",
    "- 🚫 Nunca mezcles espacios con tabulaciones. Se ven igual y Python los cuenta\n",
    "distinto, así que produce errores imposibles de ver a ojo.\n",
    "\n",
    "- ⌨️ Configura tu editor para que la tecla Tab inserte cuatro espacios. En\n",
    "Colab ya viene así."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Esto ni siquiera compila, y de eso va.** Va como texto porque una celda que no compila no se puede ejecutar; pégalo en una celda si quieres verlo.\n",
    "\n",
    "```\n",
    "if monto > 1000:\n",
    "print('sin sangria')\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Y la queja que tiene que salir es esta:\n",
    "\n",
    "```\n",
    "IndentationError: expected an indented block after 'if' statement on line 1\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## if, elif, else"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "monto = 780\n",
    "\n",
    "if monto > 2000:\n",
    "    categoria = 'Mayorista'\n",
    "elif monto > 500:\n",
    "    categoria = 'Mediana'\n",
    "elif monto > 100:\n",
    "    categoria = 'Pequeña'\n",
    "else:\n",
    "    categoria = 'Mínima'\n",
    "\n",
    "print(categoria)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Se evalúan en orden y **se sale en la primera que se cumple**. Por\n",
    "eso 780 salió como Mediana y nunca llegó a preguntarse si era mayor que 100.\n",
    "\n",
    "Ese detalle del orden es donde se cometen los errores de verdad. Mira qué pasa\n",
    "si lo escribes al revés:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "if monto > 100:\n",
    "    categoria = 'Pequeña'\n",
    "elif monto > 500:\n",
    "    categoria = 'Mediana'\n",
    "elif monto > 2000:\n",
    "    categoria = 'Mayorista'\n",
    "\n",
    "print(categoria)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Ahí ya nada puede ser Mediana ni Mayorista jamás, porque todo lo que pasa de\n",
    "500 también pasa de 100 y se sale en la primera 😬\n",
    "\n",
    "**Con rangos, siempre de más estricto a menos estricto.** Esto lo\n",
    "he visto arruinar segmentaciones enteras de clientes en empresas grandes, y no lo\n",
    "detecta ningún error: el código corre feliz.\n",
    "\n",
    "### Comparar y combinar"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "| Operador | Qué pregunta |\n",
    "|---|---|\n",
    "| `==` | ¿son iguales? Ojo, dos signos |\n",
    "| `!=` | ¿son distintos? |\n",
    "| `>` `=` `<=` | mayor, menor, y sus versiones con igual |\n",
    "| `in` | ¿está dentro de esta lista o de este texto? |\n",
    "| `and` `or` `not` | combinar condiciones |"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "ciudad = 'Lima'\n",
    "monto = 1500\n",
    "canal = 'Web'\n",
    "\n",
    "if ciudad in ['Lima', 'Callao'] and monto > 1000:\n",
    "    print('Reparto propio')\n",
    "\n",
    "if canal != 'Tienda' or monto > 5000:\n",
    "    print('Necesita seguimiento')\n",
    "\n",
    "print(100 < monto < 2000)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Esa última línea es una gracia de Python que otros lenguajes no tienen: puedes\n",
    "encadenar comparaciones como en matemáticas. Se lee lindo 🌸\n",
    "\n",
    "Y el error número uno de este capítulo:"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Esto ni siquiera compila, y de eso va.** Va como texto porque una celda que no compila no se puede ejecutar; pégalo en una celda si quieres verlo.\n",
    "\n",
    "```\n",
    "if ciudad = 'Lima':\n",
    "    print('hola')\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Y la queja que tiene que salir es esta:\n",
    "\n",
    "```\n",
    "SyntaxError: invalid syntax. Maybe you meant '==' or ':=' instead of '='?\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Un igual asigna, dos iguales comparan. Menos mal que Python te lo dice\n",
    "clarito."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## El bucle for"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Repite algo una vez por cada elemento de una lista."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "ventas = [480.37, 154.83, 2480.84]\n",
    "\n",
    "for v in ventas:\n",
    "    print(f'S/{v:,.2f}')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "El nombre `v` lo eliges tú. Ponle uno que se entienda: si recorres\n",
    "ciudades llámala `ciudad`, no `x`.\n",
    "\n",
    "Cuando necesites números y no una lista, está `range`:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "for i in range(5):\n",
    "    print(i, end=' ')\n",
    "print()\n",
    "\n",
    "for i in range(1, 4):\n",
    "    print(i, end=' ')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Igual que las rebanadas: **el final no se incluye**. Python es\n",
    "coherente con eso en todos lados, y una vez que lo interiorizas deja de\n",
    "sorprender.\n",
    "\n",
    "### enumerate, cuando necesitas la posición\n",
    "\n",
    "La tentación es llevar un contador a mano. No hace falta:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "ciudades = ['Lima', 'Arequipa', 'Cusco']\n",
    "\n",
    "for i, ciudad in enumerate(ciudades, start=1):\n",
    "    print(f'{i}. {ciudad}')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### zip, para recorrer dos listas a la vez"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "ciudades = ['Lima', 'Arequipa', 'Cusco']\n",
    "montos = [12500.5, 980.25, 145600.0]\n",
    "\n",
    "for ciudad, monto in zip(ciudades, montos):\n",
    "    print(f'{ciudad:<10} S/{monto:>12,.2f}')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Cuidado con una cosa: `zip` se detiene en la lista más corta y no\n",
    "te avisa. Si una tiene 100 elementos y la otra 98, procesas 98 y pierdes dos en\n",
    "silencio 🤫\n",
    "\n",
    "### Acumular, que es para lo que más se usa"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "ventas = [480.37, 154.83, 2480.84, 524.90]\n",
    "\n",
    "total = 0\n",
    "mayores = 0\n",
    "\n",
    "for v in ventas:\n",
    "    total = total + v\n",
    "    if v > 500:\n",
    "        mayores = mayores + 1\n",
    "\n",
    "print(f'Total S/{total:,.2f} en {len(ventas)} ventas')\n",
    "print(f'{mayores} pasaron los S/500')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Fíjate en que `total = 0` va **antes** del bucle. Si\n",
    "lo pones dentro, se reinicia en cada vuelta y terminas con el último valor en vez\n",
    "del total. Es un error clásico y silencioso."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## El bucle while"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`for` repite una vez por elemento. `while` repite\n",
    "**mientras** una condición sea verdadera, y no sabe de antemano\n",
    "cuántas veces va a ser."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "saldo = 10000\n",
    "meses = 0\n",
    "\n",
    "while saldo > 0:\n",
    "    saldo = saldo - 1500\n",
    "    meses = meses + 1\n",
    "\n",
    "print(f'Se acaba en {meses} meses, con saldo {saldo}')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Y ahora la advertencia que todo el mundo necesita una vez en la vida:"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```\n",
    "# NO ejecutes esto\n",
    "saldo = 10000\n",
    "while saldo > 0:\n",
    "    print('sigo aqui')\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Nada dentro del bucle cambia `saldo`, así que la condición nunca\n",
    "deja de cumplirse. Eso es un **bucle infinito** y tu cuaderno se\n",
    "queda colgado hasta que lo detengas 🔁\n",
    "\n",
    "La regla: **dentro de un `while`, algo tiene que mover la\n",
    "condición**. Si no lo ves a simple vista, revísalo antes de ejecutar.\n",
    "\n",
    "En Colab se corta con el botón de stop de la celda, y si quedó muy trabado,\n",
    "Entorno de ejecución y después Reiniciar. No pasa nada, no rompiste nada.\n",
    "\n",
    "### break y continue"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "montos = [120.0, 340.5, -50.0, 890.0, 1200.0]\n",
    "\n",
    "for m in montos:\n",
    "    if m < 0:\n",
    "        print('Monto negativo, algo esta mal en el archivo')\n",
    "        break\n",
    "    print(f'Procesando S/{m}')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "for m in montos:\n",
    "    if m < 0:\n",
    "        continue\n",
    "    print(f'Procesando S/{m}')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`break` sale del bucle entero. `continue` se salta esa\n",
    "vuelta y sigue con la siguiente. Los dos sirven, y elegir cuál depende de si el\n",
    "dato raro es un aviso para parar o algo que simplemente se ignora."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Preguntas que se responden sin bucle"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Hay un patrón que vas a escribir mil veces sin darte cuenta: un bucle con una\n",
    "variable que empieza en `False` y se pone en `True` si pasa\n",
    "algo. Se llama bandera, y casi siempre sobra 🚩"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "montos = [480.37, 154.83, 2480.84, -12.0, 524.90]\n",
    "\n",
    "hay_negativo = False\n",
    "for m in montos:\n",
    "    if m < 0:\n",
    "        hay_negativo = True\n",
    "        break\n",
    "print('con bucle y bandera:', hay_negativo)\n",
    "\n",
    "print('con any          :', any(m < 0 for m in montos))\n",
    "print('todos positivos  :', all(m > 0 for m in montos))\n",
    "print('cuantos negativos:', sum(m < 0 for m in montos))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Siete líneas contra una, y la de una se lee en voz alta: *¿hay alguno\n",
    "menor que cero?* 🙂\n",
    "\n",
    "- ✅ `any(...)` es **¿hay al menos uno?**\n",
    "\n",
    "- 🔒 `all(...)` es **¿lo cumplen todos?**\n",
    "\n",
    "- 🔢 `sum(...)` con una condición dentro es\n",
    "**¿cuántos?**, y funciona porque `True` vale 1 y\n",
    "`False` vale 0, que ya lo viste en el capítulo de variables.\n",
    "\n",
    "Y una cosa que no se nota: `any` también para en cuanto encuentra\n",
    "uno, igual que el `break`. Si el primer monto ya es negativo, no mira\n",
    "los tres mil restantes 🏃‍♀️"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## El else del for, que casi nadie conoce"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Un `for` puede llevar `else`. Y no significa lo que\n",
    "parece 👀"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "codigos = ['C0045', 'C0325', 'C0260']\n",
    "buscado = 'C0777'\n",
    "\n",
    "for c in codigos:\n",
    "    if c == buscado:\n",
    "        print('encontrado:', c)\n",
    "        break\n",
    "else:\n",
    "    print(buscado, 'no esta en la lista de', len(codigos), 'codigos')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "El `else` del bucle corre **cuando el bucle terminó sin\n",
    "romperse**. O sea: cuando no hubo `break`.\n",
    "\n",
    "Léelo como \"si no encontré nada\", que es para lo único que se usa. Es la\n",
    "respuesta a la pregunta más común de todas: *busqué y no estaba, ¿ahora\n",
    "qué?*"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "for c in codigos:\n",
    "    if c == 'C0325':\n",
    "        print('encontrado:', c)\n",
    "        break\n",
    "else:\n",
    "    print('no aparecio')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Aquí sí hubo `break`, así que el `else` no corrió.\n",
    "\n",
    "Sin esto, la alternativa es la bandera de la sección anterior otra vez. Y a mí\n",
    "me costó años enterarme de que existía, así que ahí lo tienes desde el principio\n",
    "en vez de dentro de diez años 💜"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## match, para las cadenas largas de elif"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Cuando el `elif` se repite cinco veces preguntando siempre por lo\n",
    "mismo, hay una forma más limpia. Existe desde Python 3.10:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def etiqueta(canal):\n",
    "    match canal:\n",
    "        case 'Web' | 'Marketplace':\n",
    "            return 'digital'\n",
    "        case 'Tienda':\n",
    "            return 'presencial'\n",
    "        case 'WhatsApp':\n",
    "            return 'mensajeria'\n",
    "        case _:\n",
    "            return 'sin clasificar'\n",
    "\n",
    "\n",
    "for canal in ['Web', 'Tienda', 'WhatsApp', 'Marketplace', 'Feria']:\n",
    "    print(f'{canal:<12} -> {etiqueta(canal)}')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Tres detalles y ya lo sabes usar 🎯\n",
    "\n",
    "- ➕ La barra `|` junta varios casos en la misma rama, que es lo que\n",
    "en `if` serían dos comparaciones con `or`.\n",
    "\n",
    "- 🅰️ El `case _` del final es el \"cualquier otra cosa\". Ponlo\n",
    "siempre, o los valores que no previste se van sin respuesta.\n",
    "\n",
    "- 🚫 No hace falta `break` entre casos. Si vienes de otros lenguajes\n",
    "donde sí hacía falta, aquí no.\n",
    "\n",
    "¿Cuándo uso `match` y cuándo `if`? Si comparas\n",
    "**una misma cosa contra varios valores**, `match`. Si\n",
    "cada rama pregunta algo distinto, `if` y `elif`. Y con dos\n",
    "ramas, `if` siempre: `match` ahí solo hace ruido."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## El bucle que no hay que escribir"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Este te lo va a sugerir cualquier buscador y viene de otros lenguajes:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "ciudades = ['Lima', 'Arequipa', 'Cusco']\n",
    "\n",
    "for i in range(len(ciudades)):\n",
    "    print(ciudades[i].upper(), end=' ')\n",
    "print()\n",
    "\n",
    "for ciudad in ciudades:\n",
    "    print(ciudad.upper(), end=' ')\n",
    "print()\n",
    "\n",
    "for i, ciudad in enumerate(ciudades, start=1):\n",
    "    print(f'{i}. {ciudad}', end='  ')\n",
    "print()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Los tres imprimen bien. El primero es el que no quiero que escribas 🙅‍♀️\n",
    "\n",
    "`range(len(algo))` te da posiciones, y luego tienes que ir a buscar\n",
    "el valor con `algo[i]`. Son dos pasos para lo que Python hace en uno, y\n",
    "cada `[i]` es una oportunidad de equivocarte de índice.\n",
    "\n",
    "La regla: si dentro del bucle solo usas `ciudades[i]`, recorre la\n",
    "lista directamente. Si de verdad necesitas el número, `enumerate`. El\n",
    "`range(len(...))` no hace falta nunca 🌸"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Un caso completo"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Vamos a juntar todo con algo que sí harías en el trabajo: clasificar ventas y\n",
    "sacar un resumen."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "ventas = [\n",
    "    {'ciudad': 'Lima', 'monto': 2480.84, 'pagado': True},\n",
    "    {'ciudad': 'Cusco', 'monto': 154.83, 'pagado': False},\n",
    "    {'ciudad': 'Lima', 'monto': 780.0, 'pagado': True},\n",
    "    {'ciudad': 'Piura', 'monto': 95.5, 'pagado': False},\n",
    "    {'ciudad': 'Lima', 'monto': 3200.0, 'pagado': True},\n",
    "]\n",
    "\n",
    "cobrado = 0\n",
    "por_cobrar = 0\n",
    "categorias = {}\n",
    "\n",
    "for v in ventas:\n",
    "    if v['pagado']:\n",
    "        cobrado = cobrado + v['monto']\n",
    "    else:\n",
    "        por_cobrar = por_cobrar + v['monto']\n",
    "\n",
    "    if v['monto'] > 2000:\n",
    "        cat = 'Mayorista'\n",
    "    elif v['monto'] > 500:\n",
    "        cat = 'Mediana'\n",
    "    else:\n",
    "        cat = 'Pequeña'\n",
    "\n",
    "    categorias[cat] = categorias.get(cat, 0) + 1\n",
    "\n",
    "print(f'Cobrado    S/{cobrado:,.2f}')\n",
    "print(f'Por cobrar S/{por_cobrar:,.2f}')\n",
    "print(categorias)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Treinta líneas y ya es un reporte que alguien podría pedirte. Con pandas van a\n",
    "ser cuatro, pero ahora entiendes qué está haciendo por dentro 💜"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Ejercicios"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 1. Semáforo de stock\n",
    "\n",
    "Dado un número de unidades, imprime \"Crítico\" si es menor a\n",
    "10, \"Bajo\" si es menor a 50, y \"OK\" en el resto de casos."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%revisa 1\n",
    "# tu turno"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 2. Suma solo lo que corresponde\n",
    "\n",
    "De una lista de montos, suma solo los positivos y cuenta\n",
    "cuántos negativos descartaste."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%revisa 2\n",
    "# tu turno"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 3. Tabla numerada\n",
    "\n",
    "Imprime una lista de ciudades numerada desde 1, alineando el\n",
    "número a la derecha en dos espacios."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%revisa 3\n",
    "# tu turno"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 4. Dos listas a la vez\n",
    "\n",
    "Con una lista de productos y otra de stock, imprime solo los\n",
    "que tengan menos de 20 unidades."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%revisa 4\n",
    "# tu turno"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 5. Cuántos meses hasta la meta\n",
    "\n",
    "Empiezas con S/5.000 y ahorras S/800 al mes. ¿Cuántos meses\n",
    "hasta llegar a S/20.000? Usa `while`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%revisa 5\n",
    "# tu turno"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 6. Parar en el primer problema\n",
    "\n",
    "Recorre una lista de códigos de cliente y detente en cuanto\n",
    "encuentres uno vacío, avisando en qué posición estaba."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%revisa 6\n",
    "# tu turno"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 7. El acumulador mal puesto\n",
    "\n",
    "Escribe a propósito el error de inicializar el total dentro\n",
    "del bucle y explica el resultado."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%revisa 7\n",
    "# tu turno"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 8. Filtrar por dos condiciones\n",
    "\n",
    "De una lista de ventas, cuenta las que son de Lima\n",
    "**y** pasan de S/1.000."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%revisa 8\n",
    "# tu turno"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 9. La comparación encadenada\n",
    "\n",
    "Clasifica un puntaje de satisfacción del 1 al 5 usando una\n",
    "comparación encadenada para validar que esté en rango."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%revisa 9\n",
    "# tu turno"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 10. El bucle que se pasa\n",
    "\n",
    "Un cliente debe S/3.000 y paga S/700 al mes. Muestra el\n",
    "saldo mes a mes hasta que quede en cero o negativo."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%revisa 10\n",
    "# tu turno"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 11. Cuatro preguntas sin escribir un bucle\n",
    "\n",
    "Responde con `any`, `all` y\n",
    "`sum`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%revisa 11\n",
    "# tu turno"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 12. Buscar, y decir algo cuando no está\n",
    "\n",
    "Usa el `else` del `for` para los dos\n",
    "casos."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%revisa 12\n",
    "# tu turno"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 13. Clasificar ciudades con `match`\n",
    "\n",
    "Agrupa las ciudades en macrorregiones."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%revisa 13\n",
    "# tu turno"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 14. Borrar mientras recorres, que es el bug silencioso\n",
    "\n",
    "Quita los montos negativos de una lista de dos maneras y\n",
    "compara."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%revisa 14\n",
    "# tu turno"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## El if más común de todos y el día que dice mentiras"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Ya viste que en Python muchas cosas se comportan como falsas sin ser False. Aquí está lo que pasa cuando eso se cuela en una comprobación que parece de manual 🚨"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### La trampa\n",
    "\n",
    "Compruebas si la consulta devolvió algo antes de seguir, que es lo responsable. Y un día el informe sale vacío sin que nadie se entere.\n",
    "\n",
    "```\n",
    "ventas = buscar(ciudad, mes)\n",
    "\n",
    "if ventas:\n",
    "    generar_informe(ventas)\n",
    "else:\n",
    "    avisar('sin conexion a la base')\n",
    "```\n",
    "\n",
    "**¿Qué está mal?** La respuesta está en el cuaderno de soluciones. Míralo tú primero."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Comprueba que lo tienes\n",
    "\n",
    "Recorres una lista con un for y dentro vas borrando elementos. ¿Qué esperas?\n",
    "\n",
    "a) Que se salte elementos, porque los índices se corren\n",
    "\n",
    "b) Que funcione, porque Python revisa la lista en cada vuelta\n",
    "\n",
    "c) Que reviente con un error\n",
    "\n",
    "d) Que borre de más"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Lo que te llevas"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- 📏 La sangría es sintaxis: cuatro espacios, sin mezclar con tabulaciones.\n",
    "\n",
    "- 🪜 En una cadena de `elif` con rangos, siempre del más estricto al\n",
    "menos estricto.\n",
    "\n",
    "- 🔢 En `range` y en las rebanadas, el final no se incluye.\n",
    "\n",
    "- ➕ El acumulador se inicializa **antes** del bucle.\n",
    "\n",
    "- ♾️ En un `while`, algo dentro tiene que mover la condición.\n",
    "\n",
    "Y si de todo el capítulo te llevas una sola frase, que sea esta:"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Preguntar si algo existe y preguntar si algo está vacío no son la misma\n",
    "pregunta."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Los `if` anidados que acabas de aprender a no escribir son,\n",
    "línea por línea, los SI dentro de SI dentro de SI que hay en medio Excel del\n",
    "país. En la [guía de Excel](https://missyera.com/guias/excel-desde-cero/) están\n",
    "contados desde el otro lado 🧩\n",
    "\n",
    "En el capítulo 6 vamos a empaquetar todo esto en funciones, que es lo que hace\n",
    "que dejes de copiar y pegar el mismo bloque en cinco sitios.\n",
    "\n",
    "Que tengas lindo día! 🌸"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Preguntas frecuentes"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "¿Cómo funciona el while en Python?Repite mientras la condición siga siendo verdadera. El riesgo es que nunca deje de serlo, y ahí el programa se queda dando vueltas para siempre.\n",
    "\n",
    "¿Cuál es la diferencia entre for y while?El for recorre algo que ya existe y sabe cuándo termina. El while repite hasta que se cumpla una condición, y puede no terminar nunca.\n",
    "\n",
    "¿Qué hacen break y continue?break corta el bucle entero y sigue con lo de después. continue se salta solo esta vuelta y pasa a la siguiente.\n",
    "\n",
    "¿Por qué Python usa indentación?Porque el bloque de código se define por los espacios y no por llaves. Mezclar tabuladores y espacios da un error que confunde, y la solución es dejar que el editor ponga cuatro espacios siempre."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "---\n",
    "\n",
    "Ese era el capítulo 5 de **Python desde cero**. El texto completo, con las salidas de cada bloque, está en https://missyera.com/guias/python-desde-cero/control-de-flujo/\n",
    "\n",
    "Que tengas lindo día! 🌸"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "name": "python",
   "version": "3.11"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
