class: center, middle, inverse, title-slide .title[ # Estructuras de Datos ] .subtitle[ ## MAD-UdelaR ] .author[ ### Daniel Miles Touya ] .date[ ### 2025-06-16 ] --- <style> .scroll-output { max-height: 300px; overflow-y: auto; background: #f9f9f9; border: 1px solid #ccc; padding: 10px; font-family: monospace; font-size: 70%; white-space: pre-wrap; } </style> # Estructura de Datos Una <b style="color:brown">estructura de datos</b> en Python es una forma de **organizar, almacenar y acceder a la información** para que pueda ser usada de manera eficiente. Permiten: * Agrupar múltiples valores * Ordenarlos o no * Acceder a ellos por índice, clave, etc. * Modificarlos (o no) >Tipos de estructuras de datos `built-in`: >> Listas >> Tuplas >> Diccionarios >> Sets (conjuntos) --- # Estuctura de datos Python ofrece varias librerías que definen y ofrecen estructuras de datos específicas y optimizadas: **Cálculo numérico / matrices grandes** | Librería | Estructura de datos principal | Para qué se usa | | -------- | ----------------------------- | ------------------------------------------- | | `NumPy` | `ndarray` | Arreglos numéricos multidimensionales | | `SciPy` | `sparse matrix` | Matrices dispersas (sparse), álgebra lineal | | `xarray` | `DataArray`, `Dataset` | Datos etiquetados en múltiples dimensiones | --- # Estuctura de datos **Análisis de datos / tabulares** | Librería | Estructura de datos principal | Para qué se usa | | ----------- | ----------------------------- | --------------------------------------------------------- | | `pandas` | `Series`, `DataFrame` | Datos tabulares (tipo Excel o SQL) | | `datatable` | `Frame` | Muy eficiente para grandes datasets (como R `data.table`) | | `polars` | `DataFrame` | Alternativa rápida a pandas, escrita en Rust | --- # Estuctura de datos **Aprendizaje automático / tensores** | Librería | Estructura de datos principal | Para qué se usa | | ------------ | ----------------------------- | ---------------------------------------- | | `TensorFlow` | `Tensor` | Tensores multidimensionales para ML / DL | | `PyTorch` | `Tensor` | Lo mismo, pero con enfoque dinámico | | `JAX` | `DeviceArray` | Tensores + diferenciación automática | --- # Estuctura de datos **Gráficos / geometría / espacial** | Librería | Estructura de datos principal | Para qué se usa | | ----------- | -------------------------------- | -------------------------------------- | | `shapely` | `Polygon`, `Point`, `LineString` | Geometría y análisis espacial 2D | | `GeoPandas` | `GeoDataFrame` | Datos tabulares con soporte geográfico | | `networkx` | `Graph`, `DiGraph` | Representación de redes y grafos | --- # Estuctura de datos **Otros tipos especializados** | Librería | Estructura principal | Para qué se usa | | ------------- | ------------------------------------------------ | ---------------------------------------------- | | `collections` | `deque`, `Counter`, `defaultdict`, `OrderedDict` | Estructuras extendidas built-in | | `sympy` | `Symbol`, `Expr` | Manipulación simbólica (álgebra computacional) | | `bitarray` | `bitarray` | Representación eficiente de bits | --- # Estucturas de Datos: Built-in Las <b style="color:brown">estructuras de datos</b> `built-in` como `list`, `dict`, `set` y `tuple` son fundamentales porque forman la base de cómo se representa, organiza y manipula la información. > **->** Casi todo lo que hacemos en Python —desde leer un archivo, procesar texto, trabajar con JSON, hacer loops o definir argumentos en funciones— se apoya en estas estructuras. > **->** Están óptimizadas: Python implementa estas estructuras de forma eficiente y rápida > **->** Facilitan el pensamiento lógico y la resolución de problemas por su sencillez > **->** Se integran perfectamente con el resto del lenguaje > **->** Son la base de estructuras más complejas: librerías como pandas, numpy, scikit-learn, etc., se construyen a partir de estas estructuras o las usan internamente. Por ejemplo: --- # Estucturas de Datos: List (lista) - Dictionary - Tuple - Sets <table style="font-size:16px; border-collapse: collapse; width: 100%;"> <thead style="background-color:#f2f2f2;"> <tr> <th>Característica</th> <th>Lista</th> <th>Ejemplo Lista</th> <th>Diccionario</th> <th>Ejemplo Diccionario</th> <th>Tupla</th> <th>Ejemplo Tupla</th> </tr> </thead> <tbody> <tr> <td><b style="color:#6082B6">Creación</b></td> <td>[] o list()</td> <td>[1, 2, 3]</td> <td>{} o dict()</td> <td>{'a': 1, 'b': 2}</td> <td>() o tuple()</td> <td>(1, 2, 3)</td> </tr> <tr> <td><b style="color:#6082B6">Indexación</b></td> <td>Sí, por posición</td> <td>lista[0] → 1</td> <td>Sí, por clave</td> <td>dic['a'] → 1</td> <td>Sí, por posición</td> <td>tupla[1] → 2</td> </tr> <tr> <td><b style="color:#6082B6">Mutabilidad</b></td> <td>✅ Sí</td> <td>lista[1] = 99</td> <td>✅ Sí</td> <td>dic['b'] = 42</td> <td>❌ No</td> <td>-</td> </tr> <tr> <td><b style="color:#6082B6">Elementos únicos</b></td> <td>No requerido</td> <td>[1, 1, 2]</td> <td>Claves únicas</td> <td>{'a': 1, 'a': 2} → {'a': 2}</td> <td>No requerido</td> <td>(1, 1, 2)</td> </tr> <tr> <td><b style="color:#6082B6">Orden</b></td> <td>✅ Desde Python 3.7</td> <td>[1,2,3] == [1,2,3]</td> <td>✅ Desde Python 3.7</td> <td>{'a': 1, 'b': 2}</td> <td>✅ Siempre</td> <td>(1, 2, 3)</td> </tr> <tr> <td><b style="color:#6082B6">Acceso por bucle</b></td> <td>✅</td> <td>for x in lista</td> <td>✅</td> <td>for k in dic</td> <td>✅</td> <td>for x in tupla</td> </tr> <tr> <td><b style="color:#6082B6">Métodos asociados</b></td> <td>Muchos (append, pop, sort...)</td> <td>lista.append(4)</td> <td>Varios (get, items...)</td> <td>dic.keys()</td> <td>Pocos (count, index)</td> <td>tupla.count(1)</td> </tr> <tr> <td><b style="color:#6082B6">Uso común</b></td> <td>Secuencia de elementos</td> <td>Nombres, edades...</td> <td>Relación clave → valor</td> <td>nombre: nota</td> <td>Datos fijos</td> <td>Coordenadas, colores</td> </tr> <tr> <td><b style="color:#6082B6">Conversión</b></td> <td>tuple(), set()</td> <td>tuple(lista)</td> <td>list(), dict()</td> <td>dict(lista_de_pares)</td> <td>list(), dict()</td> <td>list(tupla)</td> </tr> </tbody> </table> --- # Lista: Ejemplos <table style="border-collapse: collapse; width: 100%; font-size: 16px;"> <thead style="background-color: #e0e0e0;"> <tr> <th style="border: 1px solid #ccc; padding: 8px;">Acción</th> <th style="border: 1px solid #ccc; padding: 8px;">Ejemplo</th> <th style="border: 1px solid #ccc; padding: 8px;">Resultado</th> </tr> </thead> <tbody> <tr> <td style="border: 1px solid #ccc; padding: 8px;">Crear lista (mismo tipo)</td> <td style="border: 1px solid #ccc; padding: 8px;"><code>lista = [1, 2, 3]</code></td> <td style="border: 1px solid #ccc; padding: 8px;">[1, 2, 3]</td> </tr> <tr> <td style="border: 1px solid #ccc; padding: 8px;">Crear lista (tipos distintos)</td> <td style="border: 1px solid #ccc; padding: 8px;"><code>lista = [1, "hola", True]</code></td> <td style="border: 1px solid #ccc; padding: 8px;">[1, 'hola', True]</td> </tr> <tr> <td style="border: 1px solid #ccc; padding: 8px;">Indexación</td> <td style="border: 1px solid #ccc; padding: 8px;"><code>lista[1]</code></td> <td style="border: 1px solid #ccc; padding: 8px;">'hola'</td> </tr> <tr> <td style="border: 1px solid #ccc; padding: 8px;">Agregar elemento al final</td> <td style="border: 1px solid #ccc; padding: 8px;"><code>lista.append(42)</code></td> <td style="border: 1px solid #ccc; padding: 8px;">[1, 'hola', True, 42]</td> </tr> <tr> <td style="border: 1px solid #ccc; padding: 8px;">Insertar en posición</td> <td style="border: 1px solid #ccc; padding: 8px;"><code>lista.insert(1, "nuevo")</code></td> <td style="border: 1px solid #ccc; padding: 8px;">[1, 'nuevo', 'hola', True]</td> </tr> <tr> <td style="border: 1px solid #ccc; padding: 8px;">Ver si un elemento está</td> <td style="border: 1px solid #ccc; padding: 8px;"><code>"hola" in lista</code></td> <td style="border: 1px solid #ccc; padding: 8px;">True</td> </tr> <tr> <td style="border: 1px solid #ccc; padding: 8px;">Encontrar índice</td> <td style="border: 1px solid #ccc; padding: 8px;"><code>lista.index("hola")</code></td> <td style="border: 1px solid #ccc; padding: 8px;">2</td> </tr> <tr> <td style="border: 1px solid #ccc; padding: 8px;">Ordenar (números)</td> <td style="border: 1px solid #ccc; padding: 8px;"><code>lista.sort()</code></td> <td style="border: 1px solid #ccc; padding: 8px;">[1, 2, 3]</td> </tr> <tr> <td style="border: 1px solid #ccc; padding: 8px;">Crear lista vacía</td> <td style="border: 1px solid #ccc; padding: 8px;"><code>lista = []</code></td> <td style="border: 1px solid #ccc; padding: 8px;">[]</td> </tr> </tbody> </table> --- # List <table style="border-collapse: collapse; width: 100%; font-size: 16px;"> <thead style="background-color: #e0e0e0;"> <tr> <th style="border: 1px solid #ccc; padding: 8px;">Acción</th> <th style="border: 1px solid #ccc; padding: 8px;">Ejemplo</th> <th style="border: 1px solid #ccc; padding: 8px;">Resultado</th> </tr> </thead> <tbody> <tr><td style="border:1px solid #ccc;padding:8px;">Longitud</td><td style="border:1px solid #ccc;padding:8px;"><code>len([1,2,3])</code></td><td style="border:1px solid #ccc;padding:8px;">3</td></tr> <tr><td style="border:1px solid #ccc;padding:8px;">Sacar último</td><td style="border:1px solid #ccc;padding:8px;"><code>lista.pop()</code></td><td style="border:1px solid #ccc;padding:8px;">Elimina y retorna último</td></tr> <tr><td style="border:1px solid #ccc;padding:8px;">Eliminar por valor</td><td style="border:1px solid #ccc;padding:8px;"><code>lista.remove(2)</code></td><td style="border:1px solid #ccc;padding:8px;">Elimina la primera aparición de 2</td></tr> <tr><td style="border:1px solid #ccc;padding:8px;">Invertir lista</td><td style="border:1px solid #ccc;padding:8px;"><code>lista.reverse()</code></td><td style="border:1px solid #ccc;padding:8px;">Invierte orden in place</td></tr> <tr><td style="border:1px solid #ccc;padding:8px;">Vaciar lista</td><td style="border:1px solid #ccc;padding:8px;"><code>lista.clear()</code></td><td style="border:1px solid #ccc;padding:8px;">[]</td></tr> <tr><td style="border:1px solid #ccc;padding:8px;">Extender lista</td><td style="border:1px solid #ccc;padding:8px;"><code>lista.extend([4,5])</code></td><td style="border:1px solid #ccc;padding:8px;">[1,2,3,4,5]</td></tr> <tr><td style="border:1px solid #ccc;padding:8px;">Rebanado (slice)</td><td style="border:1px solid #ccc;padding:8px;"><code>lista[1:3]</code></td><td style="border:1px solid #ccc;padding:8px;">Elementos entre pos 1 y 2</td></tr> <tr><td style="border:1px solid #ccc;padding:8px;">Copiar lista</td><td style="border:1px solid #ccc;padding:8px;"><code>lista.copy()</code></td><td style="border:1px solid #ccc;padding:8px;">Nuevo objeto igual</td></tr> <tr><td style="border:1px solid #ccc;padding:8px;">Contar elementos</td><td style="border:1px solid #ccc;padding:8px;"><code>lista.count(2)</code></td><td style="border:1px solid #ccc;padding:8px;">Número de veces que aparece</td></tr> </tbody> </table> --- # List Slice: obtener elementos de una lista <p><b style="color:#6082B6">¿Qué es el slicing?</b> Es una forma de extraer una parte (sublista) de una lista en Python.</p> <pre><code>lista[inicio:fin:paso]</code></pre> <ul> <li><b style="color:#6082B6">inicio</b>: desde qué índice empezar (incluido)</li> <li><b style="color:#6082B6">fin</b>: hasta qué índice cortar (excluido)</li> <li><b style="color:#6082B6">paso</b>: cada cuántos elementos saltar</li> </ul> -- <p style="color:green">Ejemplo base:</p> <pre style="font-family: monospace; font-size: 16px; color:green"> mi_lista = ['a', 'b', 'c', 'd', 'e', 'f', 'g'] ↑ ↑ ↑ ↑ ↑ ↑ ↑ 0 1 2 3 4 5 6 </pre> -- <ul> <li><code>mi_lista[1:4]</code>-> ['b', 'c', 'd']</li> <li><code>mi_lista[:3]</code> -> ['a', 'b', 'c'] (desde el inicio)</li> <li><code>mi_lista[4:]</code> -> ['e', 'f', 'g'] (hasta el final)</li> </ul> --- # List Slicing Estructura del Slicing: <pre><code>lista[inicio:fin:paso]</code></pre> <p style="color:green">Ejemplo base:</p> <pre style="font-family: monospace; font-size: 16px; color:green"> mi_lista = ['a', 'b', 'c', 'd', 'e', 'f', 'g'] ↑ ↑ ↑ ↑ ↑ ↑ ↑ 0 1 2 3 4 5 6 </pre> <ul> <li><code>mi_lista[::2]</code> -> ['a', 'c', 'e', 'g'] (de 2 en 2)</li> <li><code>mi_lista[1:6:2]</code> -> ['b', 'd', 'f']</li> </ul> --- # List Slicing Negativo <p><b style="color:#6082B6">Los índices negativos cuentan desde el final</b>:</p> ```python mi_lista = ['a', 'b', 'c', 'd', 'e', 'f', 'g'] ``` En Python, un índice negativo cuenta desde el **final** de la lista: | Elemento | 'a' | 'b' | 'c' | 'd' | 'e' | 'f' | 'g' | | -------- | --- | --- | --- | --- | --- | --- | --- | | Índice + | 0 | 1 | 2 | 3 | 4 | 5 | 6 | | Índice – | -7 | -6 | -5 | -4 | -3 | -2 | -1 | -- .pull-left[ `mi_lista[-1]` Devuelve el **último elemento** de la lista: ```python mi_lista[-1] → 'g' ``` ] -- .pull-right[ `mi_lista[-2]` Devuelve el **penúltimo elemento**: ```python mi_lista[-2] → 'f' ``` ] --- # List Slicing Negativo <p><b style="color:#6082B6">Los índices negativos cuentan desde el final</b>:</p> | Elemento | 'a' | 'b' | 'c' | 'd' | 'e' | 'f' | 'g' | | -------- | --- | --- | --- | --- | --- | --- | --- | | Índice + | 0 | 1 | 2 | 3 | 4 | 5 | 6 | | Índice – | -7 | -6 | -5 | -4 | -3 | -2 | -1 | .pull-left[ `mi_lista[-3:-1]` Aquí usamos **slicing**, que sigue esta forma: ```python mi_lista[inicio:fin] ``` Incluye el índice de `inicio` pero **excluye** el índice `fin`. ] -- .pull-right[ * `-3` → posición de `'e'` * `-1` → posición de `'g'`, pero como se excluye: **se queda en `'f'`** ```python mi_lista[-3:-1] → ['e', 'f'] ``` ] -- <b style="color:brown">¿Por qué no incluye 'g'?</b> Porque <b style="color:green">el índice final nunca se incluye en un slice</b>, ni aunque sea negativo. Si se quiere incluir `'g'`: ```python mi_lista[-3:] → ['e', 'f', 'g'] ``` --- # Lista Slcing Negativo Reverse order: (invertido) <ul> <li><code>mi_lista[::-1]</code> -> ['g', 'f', 'e', 'd', 'c', 'b', 'a'] (lista al revés)</li> <li><code>mi_lista[5:1:-1]</code> -> ['f', 'e', 'd', 'c']</li> </ul> --- # Lista Slcing: ¿Qué hay detrás ? ¿Cómo funciona internamente `lista[inicio:fin:paso]`? -- .pull-left[ Cuando se escribe: ```python mi_lista[inicio:fin:paso] ``` ] -- .pull-right[ Python lo traduce (de forma conceptual) en: ```python resultado = [] for i in range(inicio, fin, paso): resultado.append(mi_lista[i]) ``` <b style="color:gray">Ya veremos el loop</b> Para ver que hace, pongamos un `print(i)` <a href="https://docs.python.org/2/library/functions.html?highlight=range#range" target = "_blank">range built-in</a> ] -- .pull-right[ <b style="color:green">La clave está en</b> `range(inicio, fin, paso)` ````python list(range(1,10,2)) ->Indices [1,3,5,7,9] list(range(-1,-10,-2))->Indices [-1, -3, -5, -7, -9] ```` ] --- # Lista Slcing: ¿Qué hay detrás ? Y, en definitiva, quedaría ````python mi_lista = ['a', 'b', 'c', 'd', 'e', 'f', 'g'] [mi_lista[i] for i in range(0, len(mi_lista), 2)] # ['a', 'c', 'e', 'g'] ```` <b style="color:gray">Ya veremos list comprehension</b> -- Si los indices son negativos ````python mi_lista = ['a', 'b', 'c', 'd', 'e', 'f', 'g'] [mi_lista[i] for i in range(-1, -len(mi_lista)-1, -2)] # ['g', 'e', 'c', 'a'] ```` --- # Lista Slcing: ¿Qué hay detrás ? Ejemplo: `mi_lista[5:2:-1]` ```python mi_lista = ['a', 'b', 'c', 'd', 'e', 'f', 'g'] # índices: 0 1 2 3 4 5 6 ``` Veamos cómo trabaja: ```python resultado = [] for i in range(5, 2, -1): resultado.append(mi_lista[i]) ``` -️> `range(5, 2, -1)` genera: `[5, 4, 3]` Entonces: ```python resultado = [mi_lista[5], mi_lista[4], mi_lista[3]] = ['f', 'e', 'd'] ``` --- # Lista Slcing: ¿Qué hay detrás ? Ejemplo: `mi_lista[::-1]` (inversión total) ```python resultado = [] for i in range(len(mi_lista)-1, -1, -1): resultado.append(mi_lista[i]) ``` `range(6, -1, -1)` → `[6, 5, 4, 3, 2, 1, 0]` ```python resultado = ['g', 'f', 'e', 'd', 'c', 'b', 'a'] ``` --- # Lista Slcing: ¿Qué hay detrás ? Ejemplo: `mi_lista[-1:-5:-1]` Recordando: ```python # mi_lista = ['a', 'b', 'c', 'd', 'e', 'f', 'g'] # índices: 0 1 2 3 4 5 6 # negativos:-7 -6 -5 -4 -3 -2 -1 ``` ```python resultado = [] for i in range(-1, -5, -1): resultado.append(mi_lista[i]) ``` `range(-1, -5, -1)` → `[-1, -2, -3, -4]` Entonces: ```python resultado = [mi_lista[-1], mi_lista[-2], mi_lista[-3], mi_lista[-4]] = ['g', 'f', 'e', 'd'] ``` --- # List: Ejercicios Ahora van a practicar haciendo ejercicios relacionados con <a href="python_ejercicios_listas.html" style="color:brown;font-weight: bold;">list</a> --- # Dictionary <p>Un <b style="color:#6082B6">diccionario</b> es una estructura de datos que almacena pares<b> key-value</b>. Es muy útil cuando queremos asociar una clave única a un valor.</p> <pre><code>persona = { "nombre": "Ana", "edad": 30, "ciudad": "Madrid" }</code></pre> -- <p>Para acceder a un valor, se usa su <b style="color:#6082B6">clave</b> entre corchetes:</p> <pre><code>persona = { "nombre": "Ana", "edad": 30, "ciudad": "Madrid" } print(persona["nombre"]) # Ana print(persona["edad"]) # 30 </code></pre> <p><b style="color:#6082B6">Importante:</b> Si usas una clave que no existe, se produce un error <code>KeyError</code>.</p> --- # Dictionary: `key` Las **claves (`keys`)** de un diccionario deben ser <b style="color:brown">hashables</b>. > Un objeto es <b style="color:brown">hashables</b> si: 1. Tiene un valor de **hash fijo** durante su vida (`__hash__()`). 2. Puede ser **comparado con otros objetos** (`__eq__()`). 3. Es **inmutable**, al menos desde el punto de vista del valor que afecta al hash. --- # Dictionary: `key` Un **hash** es un número entero deterministico: el mismo objeto siempre da el mismo hash. > Sirve para representar rápidamente un objeto (como una cadena, número o tupla) con un número fijo >> Los diccionarios (`dict`) y conjuntos (`set`) usan hashes para **localizar elementos sin tener que recorrerlos todos**. >>Esto hace que buscar sea muy eficiente: --- # Dictionary: `key` Ejemplos de **objetos hashables** (válidos como claves) ```python # Todos estos son válidos como claves dic = { 42: "entero", "nombre": "cadena", (1, 2): "tupla inmutable" } ``` -- Ejemplos de **objetos no hashables** (no se pueden usar como claves) ```python dic = { [1, 2, 3]: "lista", # List no es hashable {1, 2}: "conjunto", # set tampoco es hashable } ``` Estas estructuras son **mutables**, por lo tanto su valor hash podría cambiar y romper la estructura del diccionario. --- # Dictionary: `key` | Tipo | ¿Hashable? | ¿Se puede usar como clave? | | ------------------- | ---------- | -------------------------- | | `int`, `float` | ✅ Sí | ✅ Sí | | `str`, `bool` | ✅ Sí | ✅ Sí | | `tuple` (inmutable) | ✅ Sí | ✅ Sí | | `list` | ❌ No | ❌ No | | `dict`, `set` | ❌ No | ❌ No | --- # Dictionary <p>Para <b style="color:#6082B6">agregar</b> o <b style="color:#6082B6">modificar</b> una entrada asignando un valor a una clave:</p> <pre><code>persona = {"nombre": "Ana", "edad": 30} # Agregar persona["ciudad"] = "Madrid" # Modificar persona["edad"] = 31 print(persona) # {'nombre': 'Ana', 'edad': 31, 'ciudad': 'Madrid'} </code></pre> -- <p>Para <b style="color:#6082B6">eliminar</b> una clave, usá <code>del</code>:</p> <pre><code>del persona["ciudad"] print(persona) # {'nombre': 'Ana', 'edad': 31} </code></pre> --- #Métodos útiles de los diccionarios <p>Los diccionarios tienen muchos métodos útiles. Aquí están algunos de los más comunes:</p> <ul style="color:gray;font-size:18px;"> <li><b style="color:#6082B6">.get(clave)</b> → Devuelve el valor asociado a la clave o <code>None</code> si no existe.</li> <li><b style="color:#6082B6">.keys()</b> → Devuelve una vista de todas las claves.</li> <li><b style="color:#6082B6">.values()</b> → Devuelve una vista de todos los valores.</li> <li><b style="color:#6082B6">.items()</b> → Devuelve pares clave-valor como tuplas.</li> <li><b style="color:#6082B6">.pop(clave)</b> → Elimina una clave y devuelve su valor.</li> </ul> -- <pre><code>persona = {"nombre": "Ana", "edad": 30} # Obtener valor de una clave print(persona.get("nombre")) # Ana print(persona.get("ciudad")) # None # Claves, valores, items print(persona.keys()) # dict_keys(['nombre', 'edad']) print(persona.values()) # dict_values(['Ana', 30]) print(persona.items()) # dict_items([('nombre', 'Ana'), ('edad', 30)]) # pop edad = persona.pop("edad") print(edad) # 30 print(persona) # {'nombre': 'Ana'} </code></pre> --- # Dictionary `defaultdict` <p>Con un <b style="color:#6082B6">diccionario tradicional</b>, acceder a una clave inexistente genera un error:</p> <pre><code>mi_dic = {} mi_dic["manzanas"] += 1 # ❌ Error: la clave no existe</code></pre> <p style="color:gray;font-size:17px;">Este código lanza:</p> <pre><code>KeyError: 'manzanas'</code></pre> -- <p><b style="color:#6082B6">¿Solución?</b> Usar <code>defaultdict</code> para que cree un valor inicial automáticamente:</p> <a href = "https://docs.python.org/es/3.13/library/collections.html#collections.defaultdict" target = "_blank" >defaultdict</a> <pre><code>from collections import defaultdict mi_dic = defaultdict(int) # Cada clave nueva empieza en 0 mi_dic["manzanas"] += 1 print(mi_dic) # ✅ {'manzanas': 1}</code></pre> -- <ul style="font-size:18px; color:gray;"> <li>Evita tener que verificar si la clave existe.</li> <li>Ideal para <b style="color:#6082B6">contar</b> cosas automáticamente.</li> <li style="color:brown">Ya veremos lo que es <code>from collections import...</code></li> </ul> --- # Dictionary Ejercicios Ahora van a practicar haciendo ejercicios relacionados con <a href="python_ejercicios_diccionarios.html" style="color:brown;font-weight: bold;">dictionary</a> --- # Tuple Una <b style="color:#6082B6">tupla</b> es un tipo de estructura de datos en Python que sirve para **almacenar varios elementos juntos**, como una lista, pero con una diferencia importante: **las tuplas no se pueden modificar** (son *inmutables*). -- >Diferencia entre tuplas, listas y diccionarios | Tipo | Sintaxis | Mutable | Ordenado | Clave-Valor | Ejemplo | | --------------- | ---------------- | ------- | -------- | ----------- | -------------------------------- | | **Tupla** | `( )` | ❌ No | ✅ Sí | ❌ No | `("Juan", 20)` | | **Lista** | `[ ]` | ✅ Sí | ✅ Sí | ❌ No | `["Juan", 20]` | | **Diccionario** | `{clave: valor}` | ✅ Sí | ✅ Sí | ✅ Sí | `{"nombre": "Juan", "edad": 20}` | --- # Tuple >¿Cómo se crea una tupla? ```python # Tupla con varios elementos persona = ("Juan", 20, "Estudiante") # Tupla de un solo elemento (¡no olvides la coma!) solo = ("único",) # Tupla vacía vacia = () #Con `,` tupla = 3, 4 ``` --- # Tuple > Inmutable .pull-left[ Una <b style="color:#6082B6">tupla</b> **no se puede cambiar** después de ser creada. ```python persona = ("Juan", 20) # Esto NO se puede hacer persona[0] = "Pedro" ``` ] .pull-right[ Una <b style="color:#6082B6">lista</b> se puede modificar una vez que ha sido creada ````python a = [1,2,3,4] b = a b[0] = 9999 print(a) ```` ] -- >Sin embargo, si la <b style="color:#6082B6">tupla</b> **contiene** un objeto mutable, se puede modificar dicho objeto ````python tupla = ("Juan", [1,2,3]) tupla[1][2] = 9999 print(tupla) ```` --- # Tuple: uso * Cuando **no quieres que los datos cambien** (por seguridad o claridad). * Para **devolver múltiples valores** desde una función. * Para usar como **claves de diccionario** (porque son inmutables). * Para representar **registros simples**: por ejemplo, una coordenada `(x, y)`. --- # Tupla: `namedtuple` <a href="https://docs.python.org/es/3.13/library/collections.html#collections.namedtuple">namedtuple</a> * `namedtuple` es una función de la librería `collections`. * Crea tuplas **inmutables**, pero **con nombres para cada campo**. * Hace que el código sea **más legible y autodescriptivo**. ```python from collections import namedtuple # Definimos una tupla con campos con nombre Persona = namedtuple("Persona", ["nombre", "edad"]) # Creamos una instancia juan = Persona("Juan", 25) # Podemos acceder por nombre o por índice print(juan.nombre) # Juan print(juan[1]) # 25 ``` --- # `namedtuple`: utilidad en análisis funcional **Claridad y legibilidad** Funciones que devuelven múltiples valores suelen usar tuplas. Si usas `namedtuple`, sabes qué representa cada campo: ```python Punto = namedtuple("Punto", ["x", "y"]) def mover(p, dx, dy): return Punto(p.x + dx, p.y + dy) ``` -- ```python # Crear una instancia de Punto origen = Punto(3, 4) print(origen.x) print(origen.y) # Mover el punto en dx = 1 y dy = -2 nuevo_punto = mover(origen, 1, -2) print(origen) # Punto(x=3, y=4) print(nuevo_punto) # Punto(x=4, y=2) ``` --- # `namedtuple`: utilidad en análisis funcional **Estructuras más seguras y organizadas** En programación funcional, preferimos datos **inmutables** y **autoexplicativos**. `namedtuple`: * Reemplaza diccionarios (que son mutables y no tienen estructura fija). * Evita errores por índices confusos (`[0]`, `[1]`, etc.). * Permite **usar funciones puras** que trabajan con registros bien definidos. --- # `namedtuple`: utilidad en análisis funcional **Compatibilidad con funciones puras y map/filter** ```python Producto = namedtuple("Producto", ["nombre", "precio"]) productos = [Producto("pan", 1.0), Producto("leche", 1.5)] # Aplicamos funciones funcionales caros = list(filter(lambda p: p.precio > 1.0, productos)) ``` --- # Tuples <a href="python_ejercicios_tuplas.html" target = "_blank">Ejercicios Tuplas</a> --- # Sets * Un **`set`** (conjunto) es una **colección desordenada de elementos únicos**. * No tiene elementos repetidos. * Se basa en la teoría de conjuntos de matemáticas. ```python frutas = {"manzana", "pera", "naranja"} print(frutas) ``` -- | Característica | `set` | | ------------------- | -------------------- | | Tipo de colección | Desordenada | | Elementos repetidos | ❌ No se permiten | | Tipo de acceso | No hay índices | | Mutabilidad | ✅ Se puede modificar | <br> ```python repetidos = {"manzana", "manzana", "pera"} print(repetidos) # {'manzana', 'pera'} ``` --- # Sets: inicialización ```python # Con llaves colores = {"rojo", "verde", "azul"} # Con la función set() vocales = set(["a", "e", "i", "o", "u"]) # Set vacío (¡cuidado!) vacio = set() # Correcto no_es_set = {} # Esto es un diccionario ``` --- # Sets .pull-left[ Agregar y eliminar elementos ```python animales = {"perro", "gato"} animales.add("loro") animales.remove("gato") animales.discard("pez") ``` ] -- .pull-right[ No hay orden ni índices ```python numeros = {10, 20, 30} # numeros[0] # ❌ Error: los sets no tienen índice ``` ] -- Hay que usar bucles si se quiere recorrer: ```python for n in numeros: print(n) ``` --- # Sets: Operaciones de conjuntos (como en matemáticas) .pull-left[ **Unión** ```python a = {1, 2, 3} b = {3, 4, 5} print(a | b) # {1, 2, 3, 4, 5} ``` ] -- .pull-right[ **Intersección** ```python print(a & b) # {3} ``` ] -- .pull-left[ **Diferencia** ```python print(a - b) # {1, 2} print(b - a) # {4, 5} ``` ] -- .pull-right[ **Diferencia simétrica** ```python print(a ^ b) # {1, 2, 4, 5} ``` ] -- .pull-left[ **Membresía** ```python x = {1, 2} y = {1, 2, 3} print(x.issubset(y)) # True print(y.issuperset(x)) # True ``` ] --- # Sets >Comparación con listas y tuplas | Característica | `list` | `tuple` | `set` | | ----------------- | ------ | ------- | ----- | | Orden | ✅ Sí | ✅ Sí | ❌ No | | Duplicados | ✅ Sí | ✅ Sí | ❌ No | | Modificable | ✅ Sí | ❌ No | ✅ Sí | | Acceso por índice | ✅ Sí | ✅ Sí | ❌ No | -- > ¿Cuándo usar un `set`? * Cuando quieres **verificar si algo está contenido rápidamente**. * Cuando necesitas eliminar **duplicados**. * Cuando haces **operaciones matemáticas entre grupos**. * Cuando no importa el orden. --- # Sets >Ejemplo práctico ```python nombres = ["Ana", "Luis", "Ana", "Luis", "Sofía"] # Quitar duplicados unicos = set(nombres) print(unicos) # {'Luis', 'Ana', 'Sofía'} # Saber si un nombre está print("Luis" in unicos) # True ``` <a href="python_ejercicios_sets.html" target = "_blank">Ejercicios</a>