diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3485325 --- /dev/null +++ b/.gitignore @@ -0,0 +1,23 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# Distribution / packaging +*.egg-info/ +dist/ +build/ + +# Virtual environments +.venv/ +venv/ +env/ + +# IDE files +.idea/ +.vscode/ +*.code-workspace + +# OS files +.DS_Store +Thumbs.db diff --git a/README.md b/README.md index ca69ccf..e9339d3 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,49 @@ -# ejercicios_python -ejercicios de lógica y entrenamiento de python +# Ejercicios Python + +Repositorio de ejercicios de Python para el entrenamiento de conceptos, lógica de programación y algoritmos, organizados por nivel de complejidad. + +## Estructura del repositorio + +``` +ejercicios_python/ +├── basico/ # Nivel 1 – Conceptos fundamentales +├── intermedio/ # Nivel 2 – Estructuras de datos y funciones avanzadas +├── avanzado/ # Nivel 3 – POO, decoradores, generadores +└── algoritmos/ # Algoritmos clásicos y estructuras de datos +``` + +## Niveles + +### 🟢 Básico +Ejercicios orientados a quienes están dando sus primeros pasos en Python. +Temas: variables, tipos de datos, condicionales, bucles y funciones simples. + +### 🟡 Intermedio +Ejercicios para quienes ya conocen lo básico y quieren profundizar. +Temas: listas avanzadas, diccionarios, funciones de orden superior, manejo de archivos y excepciones. + +### 🔴 Avanzado +Ejercicios que exploran características más potentes del lenguaje. +Temas: programación orientada a objetos, decoradores, generadores y comprensiones. + +### ⚙️ Algoritmos +Implementaciones de algoritmos y estructuras de datos clásicas. +Temas: ordenamiento, búsqueda, recursión y estructuras lineales/no lineales. + +## Cómo usar este repositorio + +1. Clona el repositorio: + ```bash + git clone https://github.com/BrandonCabra/ejercicios_python.git + ``` +2. Navega al nivel que te corresponda y abre el archivo `.py` que quieras practicar. +3. Lee el enunciado incluido como comentario al inicio de cada archivo. +4. Escribe tu solución y ejecútala con: + ```bash + python nombre_del_archivo.py + ``` + +## Requisitos + +- Python 3.8 o superior. +- No se requieren librerías externas; todos los ejercicios usan la biblioteca estándar. diff --git a/algoritmos/01_ordenamiento.py b/algoritmos/01_ordenamiento.py new file mode 100644 index 0000000..f28c14b --- /dev/null +++ b/algoritmos/01_ordenamiento.py @@ -0,0 +1,147 @@ +# ============================================================= +# Ejercicio: Algoritmos de ordenamiento +# Nivel: Algoritmos +# ============================================================= +# Descripción: +# Implementa los algoritmos de ordenamiento más conocidos +# y compara su comportamiento. +# ============================================================= + +# ------ Tarea 1: Bubble Sort ------ +# Implementa el algoritmo Bubble Sort. +# Idea: compara pares adyacentes e intercambia si están +# en el orden incorrecto; repite hasta que no haya cambios. +def bubble_sort(lista): + arr = lista[:] # No modificar la lista original + # Tu código aquí: + return arr + +datos = [64, 25, 12, 22, 11] +print("Bubble Sort:", bubble_sort(datos)) +# Esperado: [11, 12, 22, 25, 64] + + +# ------ Tarea 2: Selection Sort ------ +# Implementa Selection Sort. +# Idea: busca el mínimo del subarreglo no ordenado y lo +# coloca al inicio en cada iteración. +def selection_sort(lista): + arr = lista[:] + # Tu código aquí: + return arr + +print("Selection Sort:", selection_sort(datos)) +# Esperado: [11, 12, 22, 25, 64] + + +# ------ Tarea 3: Insertion Sort ------ +# Implementa Insertion Sort. +# Idea: toma un elemento y lo inserta en su posición correcta +# dentro del subarreglo ya ordenado. +def insertion_sort(lista): + arr = lista[:] + # Tu código aquí: + return arr + +print("Insertion Sort:", insertion_sort(datos)) +# Esperado: [11, 12, 22, 25, 64] + + +# ------ Tarea 4: Merge Sort ------ +# Implementa Merge Sort de forma recursiva. +# Idea: divide la lista en mitades, ordena cada mitad y combina. +def merge_sort(lista): + if len(lista) <= 1: + return lista + # Tu código aquí: + pass + +print("Merge Sort:", merge_sort(datos)) +# Esperado: [11, 12, 22, 25, 64] + + +# ------ Tarea 5: Quick Sort ------ +# Implementa Quick Sort de forma recursiva. +# Idea: elige un pivote, separa los menores y mayores, y ordena recursivamente. +def quick_sort(lista): + if len(lista) <= 1: + return lista + # Tu código aquí (elige el primer elemento como pivote): + pass + +print("Quick Sort:", quick_sort(datos)) +# Esperado: [11, 12, 22, 25, 64] + + +# ------ Tarea 6: Comparación de rendimiento ------ +# Usando el módulo timeit, mide cuánto tarda cada algoritmo +# en ordenar una lista de 1000 elementos aleatorios. +import timeit +import random + +grande = random.sample(range(10000), 1000) + +# Tu código aquí: mide y compara tiempos + + +# ============================================================= +# Ejemplos de solución +# ============================================================= +# --- Tarea 1 --- +# def bubble_sort(lista): +# arr = lista[:] +# n = len(arr) +# for i in range(n): +# for j in range(0, n - i - 1): +# if arr[j] > arr[j + 1]: +# arr[j], arr[j + 1] = arr[j + 1], arr[j] +# return arr + +# --- Tarea 2 --- +# def selection_sort(lista): +# arr = lista[:] +# n = len(arr) +# for i in range(n): +# idx_min = i +# for j in range(i + 1, n): +# if arr[j] < arr[idx_min]: +# idx_min = j +# arr[i], arr[idx_min] = arr[idx_min], arr[i] +# return arr + +# --- Tarea 3 --- +# def insertion_sort(lista): +# arr = lista[:] +# for i in range(1, len(arr)): +# clave = arr[i] +# j = i - 1 +# while j >= 0 and arr[j] > clave: +# arr[j + 1] = arr[j] +# j -= 1 +# arr[j + 1] = clave +# return arr + +# --- Tarea 4 --- +# def merge_sort(lista): +# if len(lista) <= 1: +# return lista +# mid = len(lista) // 2 +# izq = merge_sort(lista[:mid]) +# der = merge_sort(lista[mid:]) +# resultado = [] +# i = j = 0 +# while i < len(izq) and j < len(der): +# if izq[i] <= der[j]: +# resultado.append(izq[i]); i += 1 +# else: +# resultado.append(der[j]); j += 1 +# return resultado + izq[i:] + der[j:] + +# --- Tarea 5 --- +# def quick_sort(lista): +# if len(lista) <= 1: +# return lista +# pivote = lista[0] +# menores = [x for x in lista[1:] if x <= pivote] +# mayores = [x for x in lista[1:] if x > pivote] +# return quick_sort(menores) + [pivote] + quick_sort(mayores) diff --git a/algoritmos/02_busqueda.py b/algoritmos/02_busqueda.py new file mode 100644 index 0000000..8c7f3c5 --- /dev/null +++ b/algoritmos/02_busqueda.py @@ -0,0 +1,121 @@ +# ============================================================= +# Ejercicio: Algoritmos de búsqueda +# Nivel: Algoritmos +# ============================================================= +# Descripción: +# Implementa los algoritmos de búsqueda más comunes y +# analiza su complejidad temporal. +# ============================================================= + +# ------ Tarea 1: Búsqueda lineal ------ +# Implementa la búsqueda lineal: recorre la lista elemento +# a elemento hasta encontrar el objetivo. +# Retorna el índice si lo encuentra, o -1 si no existe. +def busqueda_lineal(lista, objetivo): + # Tu código aquí: + pass + +numeros = [5, 3, 8, 1, 9, 2, 7, 4, 6] +print(busqueda_lineal(numeros, 9)) # 4 +print(busqueda_lineal(numeros, 10)) # -1 + + +# ------ Tarea 2: Búsqueda binaria (iterativa) ------ +# La lista DEBE estar ordenada. Divide el espacio de búsqueda +# a la mitad en cada paso. +# Complejidad: O(log n) +def busqueda_binaria(lista, objetivo): + izquierda, derecha = 0, len(lista) - 1 + # Tu código aquí: + pass + +ordenada = sorted(numeros) +print("Lista ordenada:", ordenada) +print(busqueda_binaria(ordenada, 7)) # índice de 7 en la lista ordenada +print(busqueda_binaria(ordenada, 10)) # -1 + + +# ------ Tarea 3: Búsqueda binaria (recursiva) ------ +def busqueda_binaria_recursiva(lista, objetivo, izquierda=None, derecha=None): + if izquierda is None: + izquierda = 0 + if derecha is None: + derecha = len(lista) - 1 + # Tu código aquí: + pass + +print(busqueda_binaria_recursiva(ordenada, 7)) +print(busqueda_binaria_recursiva(ordenada, 10)) + + +# ------ Tarea 4: Búsqueda en matriz ------ +# Dada una matriz n×m de números enteros ordenados de forma +# que cada fila está ordenada de izquierda a derecha y la +# primera celda de cada fila es mayor que la última de la +# fila anterior, determina si un objetivo existe en la matriz. +def buscar_en_matriz(matriz, objetivo): + # Tu código aquí (pista: aplica búsqueda binaria): + pass + +matriz = [ + [1, 3, 5, 7], + [10, 11, 16, 20], + [23, 30, 34, 60], +] +print(buscar_en_matriz(matriz, 3)) # True +print(buscar_en_matriz(matriz, 13)) # False + + +# ============================================================= +# Ejemplos de solución +# ============================================================= +# --- Tarea 1 --- +# def busqueda_lineal(lista, objetivo): +# for i, valor in enumerate(lista): +# if valor == objetivo: +# return i +# return -1 + +# --- Tarea 2 --- +# def busqueda_binaria(lista, objetivo): +# izquierda, derecha = 0, len(lista) - 1 +# while izquierda <= derecha: +# medio = (izquierda + derecha) // 2 +# if lista[medio] == objetivo: +# return medio +# elif lista[medio] < objetivo: +# izquierda = medio + 1 +# else: +# derecha = medio - 1 +# return -1 + +# --- Tarea 3 --- +# def busqueda_binaria_recursiva(lista, objetivo, izquierda=None, derecha=None): +# if izquierda is None: izquierda = 0 +# if derecha is None: derecha = len(lista) - 1 +# if izquierda > derecha: +# return -1 +# medio = (izquierda + derecha) // 2 +# if lista[medio] == objetivo: +# return medio +# elif lista[medio] < objetivo: +# return busqueda_binaria_recursiva(lista, objetivo, medio + 1, derecha) +# else: +# return busqueda_binaria_recursiva(lista, objetivo, izquierda, medio - 1) + +# --- Tarea 4 --- +# def buscar_en_matriz(matriz, objetivo): +# if not matriz: +# return False +# filas, cols = len(matriz), len(matriz[0]) +# izq, der = 0, filas * cols - 1 +# while izq <= der: +# mid = (izq + der) // 2 +# valor = matriz[mid // cols][mid % cols] +# if valor == objetivo: +# return True +# elif valor < objetivo: +# izq = mid + 1 +# else: +# der = mid - 1 +# return False diff --git a/algoritmos/03_recursion.py b/algoritmos/03_recursion.py new file mode 100644 index 0000000..3f81236 --- /dev/null +++ b/algoritmos/03_recursion.py @@ -0,0 +1,139 @@ +# ============================================================= +# Ejercicio: Recursión +# Nivel: Algoritmos +# ============================================================= +# Descripción: +# La recursión es una técnica donde una función se llama a sí +# misma para resolver subproblemas más pequeños. +# Regla de oro: siempre define un caso base para detener la recursión. +# ============================================================= + +import sys +sys.setrecursionlimit(10000) + +# ------ Tarea 1: Factorial recursivo ------ +def factorial(n): + # Caso base: + # Tu código aquí: + pass + +print(factorial(5)) # 120 +print(factorial(0)) # 1 +print(factorial(10)) # 3628800 + + +# ------ Tarea 2: Fibonacci recursivo ------ +# Implementa la función de Fibonacci de forma recursiva. +# Nota: esta versión naive es O(2^n); observa cómo se ralentiza +# para valores grandes. +def fibonacci(n): + # Tu código aquí: + pass + +print([fibonacci(i) for i in range(10)]) +# Esperado: [0, 1, 1, 2, 3, 5, 8, 13, 21, 34] + + +# ------ Tarea 3: Fibonacci con memoización ------ +# Mejora la versión anterior usando un diccionario de caché +# para evitar recálculos (memoización manual o @functools.lru_cache). +from functools import lru_cache + +@lru_cache(maxsize=None) +def fibonacci_memo(n): + # Tu código aquí: + pass + +print(fibonacci_memo(50)) # 12586269025 (instantáneo) + + +# ------ Tarea 4: Torres de Hanói ------ +# Imprime los movimientos necesarios para mover n discos +# del poste origen al destino, usando un poste auxiliar. +def hanoi(n, origen="A", destino="C", auxiliar="B"): + # Tu código aquí: + pass + +hanoi(3) +# Esperado (7 movimientos): +# Mover disco 1 de A a C +# Mover disco 2 de A a B +# Mover disco 1 de C a B +# Mover disco 3 de A a C +# Mover disco 1 de B a A +# Mover disco 2 de B a C +# Mover disco 1 de A a C + + +# ------ Tarea 5: Potencia recursiva ------ +# Calcula x^n de forma recursiva eficiente usando la propiedad: +# x^n = (x^(n//2))^2 si n es par +# x^n = x * x^(n-1) si n es impar +def potencia(x, n): + # Tu código aquí: + pass + +print(potencia(2, 10)) # 1024 +print(potencia(3, 5)) # 243 +print(potencia(5, 0)) # 1 + + +# ------ Tarea 6: Suma de dígitos ------ +# Dado un número entero, calcula la suma de sus dígitos +# de forma recursiva. Ejemplo: suma_digitos(123) = 6 +def suma_digitos(n): + n = abs(n) + # Tu código aquí: + pass + +print(suma_digitos(123)) # 6 +print(suma_digitos(9999)) # 36 +print(suma_digitos(0)) # 0 + + +# ============================================================= +# Ejemplos de solución +# ============================================================= +# --- Tarea 1 --- +# def factorial(n): +# if n == 0: +# return 1 +# return n * factorial(n - 1) + +# --- Tarea 2 --- +# def fibonacci(n): +# if n <= 1: +# return n +# return fibonacci(n - 1) + fibonacci(n - 2) + +# --- Tarea 3 --- +# @lru_cache(maxsize=None) +# def fibonacci_memo(n): +# if n <= 1: +# return n +# return fibonacci_memo(n - 1) + fibonacci_memo(n - 2) + +# --- Tarea 4 --- +# def hanoi(n, origen="A", destino="C", auxiliar="B"): +# if n == 1: +# print(f"Mover disco 1 de {origen} a {destino}") +# return +# hanoi(n - 1, origen, auxiliar, destino) +# print(f"Mover disco {n} de {origen} a {destino}") +# hanoi(n - 1, auxiliar, destino, origen) + +# --- Tarea 5 --- +# def potencia(x, n): +# if n == 0: +# return 1 +# if n % 2 == 0: +# mitad = potencia(x, n // 2) +# return mitad * mitad +# return x * potencia(x, n - 1) + +# --- Tarea 6 --- +# def suma_digitos(n): +# n = abs(n) +# if n < 10: +# return n +# return n % 10 + suma_digitos(n // 10) diff --git a/algoritmos/04_estructuras_datos.py b/algoritmos/04_estructuras_datos.py new file mode 100644 index 0000000..787f3c4 --- /dev/null +++ b/algoritmos/04_estructuras_datos.py @@ -0,0 +1,223 @@ +# ============================================================= +# Ejercicio: Estructuras de datos lineales +# Nivel: Algoritmos +# ============================================================= +# Descripción: +# Implementa las estructuras de datos más importantes desde +# cero usando clases de Python: Pila, Cola y Lista enlazada. +# ============================================================= + +# ============================================================= +# Parte 1: Pila (Stack) – LIFO (Last In, First Out) +# ============================================================= +# Operaciones requeridas: +# push(dato) – añade un elemento en la cima +# pop() – elimina y retorna el elemento de la cima +# peek() – retorna el elemento de la cima sin eliminarlo +# is_empty() – True si la pila está vacía +# __len__() – número de elementos en la pila +class Pila: + def __init__(self): + self._datos = [] + + def push(self, dato): + # Tu código aquí: + pass + + def pop(self): + # Tu código aquí (lanza IndexError si está vacía): + pass + + def peek(self): + # Tu código aquí: + pass + + def is_empty(self): + # Tu código aquí: + pass + + def __len__(self): + return len(self._datos) + + def __repr__(self): + return f"Pila({self._datos})" + + +# Pruebas de Pila +pila = Pila() +pila.push(1) +pila.push(2) +pila.push(3) +print(pila) # Pila([1, 2, 3]) +print(pila.peek()) # 3 +print(pila.pop()) # 3 +print(len(pila)) # 2 +print(pila.is_empty()) # False + + +# ============================================================= +# Parte 2: Cola (Queue) – FIFO (First In, First Out) +# ============================================================= +from collections import deque + +class Cola: + def __init__(self): + self._datos = deque() + + def enqueue(self, dato): + # Tu código aquí: + pass + + def dequeue(self): + # Tu código aquí (lanza IndexError si está vacía): + pass + + def frente(self): + # Tu código aquí: + pass + + def is_empty(self): + return len(self._datos) == 0 + + def __len__(self): + return len(self._datos) + + def __repr__(self): + return f"Cola({list(self._datos)})" + + +# Pruebas de Cola +cola = Cola() +cola.enqueue("a") +cola.enqueue("b") +cola.enqueue("c") +print(cola) # Cola(['a', 'b', 'c']) +print(cola.frente()) # 'a' +print(cola.dequeue()) # 'a' +print(len(cola)) # 2 + + +# ============================================================= +# Parte 3: Lista enlazada simple +# ============================================================= +class Nodo: + def __init__(self, dato): + self.dato = dato + self.siguiente = None + + +class ListaEnlazada: + def __init__(self): + self.cabeza = None + + def agregar_al_final(self, dato): + # Tu código aquí: + pass + + def agregar_al_inicio(self, dato): + # Tu código aquí: + pass + + def eliminar(self, dato): + # Elimina la primera aparición del dato. + # Tu código aquí: + pass + + def buscar(self, dato): + # Retorna True si el dato está en la lista. + # Tu código aquí: + pass + + def __len__(self): + cuenta = 0 + actual = self.cabeza + while actual: + cuenta += 1 + actual = actual.siguiente + return cuenta + + def __repr__(self): + elementos = [] + actual = self.cabeza + while actual: + elementos.append(str(actual.dato)) + actual = actual.siguiente + return " -> ".join(elementos) + " -> None" + + +# Pruebas de Lista enlazada +lista = ListaEnlazada() +lista.agregar_al_final(1) +lista.agregar_al_final(2) +lista.agregar_al_final(3) +lista.agregar_al_inicio(0) +print(lista) # 0 -> 1 -> 2 -> 3 -> None +print(len(lista)) # 4 +print(lista.buscar(2)) # True +print(lista.buscar(9)) # False +lista.eliminar(2) +print(lista) # 0 -> 1 -> 3 -> None + + +# ============================================================= +# Ejemplos de solución +# ============================================================= +# --- Pila --- +# def push(self, dato): +# self._datos.append(dato) +# def pop(self): +# if self.is_empty(): +# raise IndexError("La pila está vacía") +# return self._datos.pop() +# def peek(self): +# if self.is_empty(): +# raise IndexError("La pila está vacía") +# return self._datos[-1] +# def is_empty(self): +# return len(self._datos) == 0 + +# --- Cola --- +# def enqueue(self, dato): +# self._datos.append(dato) +# def dequeue(self): +# if self.is_empty(): +# raise IndexError("La cola está vacía") +# return self._datos.popleft() +# def frente(self): +# return self._datos[0] + +# --- Lista enlazada --- +# def agregar_al_final(self, dato): +# nuevo = Nodo(dato) +# if not self.cabeza: +# self.cabeza = nuevo +# return +# actual = self.cabeza +# while actual.siguiente: +# actual = actual.siguiente +# actual.siguiente = nuevo + +# def agregar_al_inicio(self, dato): +# nuevo = Nodo(dato) +# nuevo.siguiente = self.cabeza +# self.cabeza = nuevo + +# def eliminar(self, dato): +# if not self.cabeza: +# return +# if self.cabeza.dato == dato: +# self.cabeza = self.cabeza.siguiente +# return +# actual = self.cabeza +# while actual.siguiente and actual.siguiente.dato != dato: +# actual = actual.siguiente +# if actual.siguiente: +# actual.siguiente = actual.siguiente.siguiente + +# def buscar(self, dato): +# actual = self.cabeza +# while actual: +# if actual.dato == dato: +# return True +# actual = actual.siguiente +# return False diff --git a/avanzado/01_poo_clases.py b/avanzado/01_poo_clases.py new file mode 100644 index 0000000..2f11bbf --- /dev/null +++ b/avanzado/01_poo_clases.py @@ -0,0 +1,170 @@ +# ============================================================= +# Ejercicio: Programación Orientada a Objetos (POO) +# Nivel: Avanzado +# ============================================================= +# Descripción: +# Diseña e implementa clases con atributos, métodos, +# herencia y polimorfismo. +# ============================================================= + +# ------ Tarea 1: Clase básica ------ +# Implementa la clase Rectangulo con: +# - Atributos: ancho, alto +# - Métodos: area(), perimetro() y __str__() +class Rectangulo: + def __init__(self, ancho, alto): + # Tu código aquí: + pass + + def area(self): + pass + + def perimetro(self): + pass + + def __str__(self): + pass + +r = Rectangulo(5, 3) +print(r.area()) # 15 +print(r.perimetro()) # 16 +print(r) # Rectangulo(ancho=5, alto=3) + + +# ------ Tarea 2: Herencia ------ +# Implementa una jerarquía de figuras: +# - Clase base Figura con método area() abstracto +# - Clase Circulo que hereda de Figura +# - Clase Triangulo que hereda de Figura +import math +from abc import ABC, abstractmethod + +class Figura(ABC): + @abstractmethod + def area(self): + pass + + @abstractmethod + def perimetro(self): + pass + +class Circulo(Figura): + def __init__(self, radio): + # Tu código aquí: + pass + + def area(self): + pass + + def perimetro(self): + pass + +class Triangulo(Figura): + def __init__(self, base, altura, lado1, lado2, lado3): + # Tu código aquí: + pass + + def area(self): + pass + + def perimetro(self): + pass + +c = Circulo(5) +print(f"Círculo - Área: {c.area():.2f}, Perímetro: {c.perimetro():.2f}") +# Área: 78.54, Perímetro: 31.42 + +t = Triangulo(6, 4, 5, 5, 6) +print(f"Triángulo - Área: {t.area():.2f}, Perímetro: {t.perimetro():.2f}") +# Área: 12.00, Perímetro: 16.00 + + +# ------ Tarea 3: Polimorfismo ------ +# Crea una lista con varias figuras y calcula el área total. +figuras = [Circulo(3), Triangulo(4, 3, 3, 4, 5), Rectangulo(7, 2)] +# Tu código aquí: itera e imprime el área de cada figura. + + +# ------ Tarea 4: Propiedades ------ +# Implementa una clase CuentaBancaria con: +# - Atributo privado _saldo +# - Propiedad saldo (solo lectura) +# - Métodos depositar(cantidad) y retirar(cantidad) +# que validen que la cantidad sea positiva y que no se +# retire más de lo disponible. +class CuentaBancaria: + def __init__(self, saldo_inicial=0): + # Tu código aquí: + pass + + @property + def saldo(self): + pass + + def depositar(self, cantidad): + pass + + def retirar(self, cantidad): + pass + +cuenta = CuentaBancaria(100) +cuenta.depositar(50) +print(cuenta.saldo) # 150 +cuenta.retirar(30) +print(cuenta.saldo) # 120 +cuenta.retirar(200) # Debe indicar fondos insuficientes + + +# ============================================================= +# Ejemplos de solución +# ============================================================= +# --- Tarea 1 --- +# class Rectangulo: +# def __init__(self, ancho, alto): +# self.ancho = ancho +# self.alto = alto +# def area(self): +# return self.ancho * self.alto +# def perimetro(self): +# return 2 * (self.ancho + self.alto) +# def __str__(self): +# return f"Rectangulo(ancho={self.ancho}, alto={self.alto})" + +# --- Tarea 2 --- +# class Circulo(Figura): +# def __init__(self, radio): +# self.radio = radio +# def area(self): +# return math.pi * self.radio ** 2 +# def perimetro(self): +# return 2 * math.pi * self.radio + +# class Triangulo(Figura): +# def __init__(self, base, altura, lado1, lado2, lado3): +# self.base = base +# self.altura = altura +# self.lados = (lado1, lado2, lado3) +# def area(self): +# return 0.5 * self.base * self.altura +# def perimetro(self): +# return sum(self.lados) + +# --- Tarea 3 --- +# for figura in figuras: +# print(f"{type(figura).__name__}: área = {figura.area():.2f}") + +# --- Tarea 4 --- +# class CuentaBancaria: +# def __init__(self, saldo_inicial=0): +# self._saldo = saldo_inicial +# @property +# def saldo(self): +# return self._saldo +# def depositar(self, cantidad): +# if cantidad > 0: +# self._saldo += cantidad +# def retirar(self, cantidad): +# if cantidad > self._saldo: +# print("Fondos insuficientes") +# elif cantidad > 0: +# self._saldo -= cantidad diff --git a/avanzado/02_decoradores.py b/avanzado/02_decoradores.py new file mode 100644 index 0000000..27ff53e --- /dev/null +++ b/avanzado/02_decoradores.py @@ -0,0 +1,138 @@ +# ============================================================= +# Ejercicio: Decoradores +# Nivel: Avanzado +# ============================================================= +# Descripción: +# Los decoradores son funciones que envuelven a otras funciones +# para añadir o modificar su comportamiento sin cambiar su código. +# Sintaxis: @mi_decorador +# ============================================================= + +import time +import functools + +# ------ Tarea 1 ------ +# Crea un decorador 'cronometrar' que imprima el tiempo que +# tarda en ejecutarse la función decorada. +def cronometrar(func): + @functools.wraps(func) + def envoltura(*args, **kwargs): + # Tu código aquí: + pass + return envoltura + +@cronometrar +def operacion_lenta(): + time.sleep(0.1) + return "Listo" + +print(operacion_lenta()) +# Esperado: "operacion_lenta tardó X.XXs" y "Listo" + + +# ------ Tarea 2 ------ +# Crea un decorador 'registrar' que imprima el nombre de la +# función y los argumentos con que fue llamada, antes de ejecutarla. +def registrar(func): + @functools.wraps(func) + def envoltura(*args, **kwargs): + # Tu código aquí: + pass + return envoltura + +@registrar +def sumar(a, b): + return a + b + +print(sumar(3, 7)) +# Esperado: +# Llamando a: sumar con args=(3, 7), kwargs={} +# 10 + + +# ------ Tarea 3 ------ +# Crea un decorador 'reintentar' que vuelva a ejecutar la función +# hasta 3 veces si lanza una excepción, y la propague al tercer fallo. +def reintentar(func): + @functools.wraps(func) + def envoltura(*args, **kwargs): + # Tu código aquí: + pass + return envoltura + +contador_llamadas = 0 + +@reintentar +def puede_fallar(): + global contador_llamadas + contador_llamadas += 1 + if contador_llamadas < 3: + raise ValueError("Error temporal") + return "Éxito en el intento 3" + +print(puede_fallar()) # Debe funcionar al tercer intento + + +# ------ Tarea 4 ------ +# Crea un decorador de fábrica 'repetir(n)' que ejecute la +# función n veces. +def repetir(n): + def decorador(func): + @functools.wraps(func) + def envoltura(*args, **kwargs): + # Tu código aquí: + pass + return envoltura + return decorador + +@repetir(3) +def saludar(nombre): + print(f"¡Hola, {nombre}!") + +saludar("Brandon") +# Esperado: imprime el saludo 3 veces + + +# ============================================================= +# Ejemplos de solución +# ============================================================= +# --- Tarea 1 --- +# def cronometrar(func): +# @functools.wraps(func) +# def envoltura(*args, **kwargs): +# inicio = time.time() +# resultado = func(*args, **kwargs) +# fin = time.time() +# print(f"{func.__name__} tardó {fin - inicio:.4f}s") +# return resultado +# return envoltura + +# --- Tarea 2 --- +# def registrar(func): +# @functools.wraps(func) +# def envoltura(*args, **kwargs): +# print(f"Llamando a: {func.__name__} con args={args}, kwargs={kwargs}") +# return func(*args, **kwargs) +# return envoltura + +# --- Tarea 3 --- +# def reintentar(func): +# @functools.wraps(func) +# def envoltura(*args, **kwargs): +# for intento in range(3): +# try: +# return func(*args, **kwargs) +# except Exception as e: +# print(f"Intento {intento + 1} fallido: {e}") +# raise +# return envoltura + +# --- Tarea 4 --- +# def repetir(n): +# def decorador(func): +# @functools.wraps(func) +# def envoltura(*args, **kwargs): +# for _ in range(n): +# func(*args, **kwargs) +# return envoltura +# return decorador diff --git a/avanzado/03_generadores.py b/avanzado/03_generadores.py new file mode 100644 index 0000000..596bbfa --- /dev/null +++ b/avanzado/03_generadores.py @@ -0,0 +1,114 @@ +# ============================================================= +# Ejercicio: Generadores e iteradores +# Nivel: Avanzado +# ============================================================= +# Descripción: +# Los generadores producen valores de forma perezosa (lazy), +# ahorrando memoria. Se crean con la palabra clave 'yield'. +# ============================================================= + +# ------ Tarea 1 ------ +# Crea un generador 'contar_hasta' que produzca números del 1 +# hasta n (incluido). +def contar_hasta(n): + # Tu código aquí (usa yield): + pass + +for num in contar_hasta(5): + print(num, end=" ") +# Esperado: 1 2 3 4 5 +print() + + +# ------ Tarea 2 ------ +# Crea un generador 'fibonacci' que produzca la secuencia de +# Fibonacci indefinidamente (sin límite). Usa islice para +# obtener los primeros 10 términos. +from itertools import islice + +def fibonacci(): + # Tu código aquí: + pass + +print(list(islice(fibonacci(), 10))) +# Esperado: [0, 1, 1, 2, 3, 5, 8, 13, 21, 34] + + +# ------ Tarea 3 ------ +# Crea un generador 'lineas_archivo' que lea un archivo línea +# a línea sin cargarlo todo en memoria (modo lazy). +# Para la prueba, escribe primero el archivo y luego léelo. +import os + +def lineas_archivo(ruta): + # Tu código aquí: + pass + +# Crear archivo de prueba +with open("/tmp/prueba.txt", "w") as f: + f.writelines(f"Línea {i}\n" for i in range(1, 6)) + +for linea in lineas_archivo("/tmp/prueba.txt"): + print(linea, end="") +# Esperado: Línea 1 a Línea 5 + + +# ------ Tarea 4 ------ +# Convierte el siguiente generador en una expresión generadora +# (generator expression) equivalente y compara el uso de memoria. + +def cuadrados_gen(n): + for x in range(1, n + 1): + yield x ** 2 + +# Escribe la expresión generadora equivalente: +# cuadrados_expr = (... for ... in ...) +cuadrados_expr = None # Reemplaza None con tu expresión generadora + +print(list(cuadrados_gen(5))) # [1, 4, 9, 16, 25] +# print(list(cuadrados_expr)) # Debe dar el mismo resultado + + +# ------ Tarea 5 ------ +# Encadena dos generadores con 'yield from': crea un generador +# que produzca primero los números del 1 al 5 y luego del 6 al 10. +def rango_completo(): + # Tu código aquí (usa yield from): + pass + +print(list(rango_completo())) +# Esperado: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] + +# Limpieza +if os.path.exists("/tmp/prueba.txt"): + os.remove("/tmp/prueba.txt") + + +# ============================================================= +# Ejemplos de solución +# ============================================================= +# --- Tarea 1 --- +# def contar_hasta(n): +# for i in range(1, n + 1): +# yield i + +# --- Tarea 2 --- +# def fibonacci(): +# a, b = 0, 1 +# while True: +# yield a +# a, b = b, a + b + +# --- Tarea 3 --- +# def lineas_archivo(ruta): +# with open(ruta, "r", encoding="utf-8") as f: +# for linea in f: +# yield linea + +# --- Tarea 4 --- +# cuadrados_expr = (x ** 2 for x in range(1, 6)) + +# --- Tarea 5 --- +# def rango_completo(): +# yield from range(1, 6) +# yield from range(6, 11) diff --git a/basico/01_variables_y_tipos.py b/basico/01_variables_y_tipos.py new file mode 100644 index 0000000..1e45130 --- /dev/null +++ b/basico/01_variables_y_tipos.py @@ -0,0 +1,54 @@ +# ============================================================= +# Ejercicio: Variables y tipos de datos +# Nivel: Básico +# ============================================================= +# Descripción: +# Practica la declaración de variables con los tipos de datos +# más comunes en Python: int, float, str y bool. +# Cada bloque propone una tarea concreta; reemplaza los "..." +# por tu código. +# ============================================================= + +# ------ Tarea 1 ------ +# Declara una variable entera con tu edad y muéstrala en pantalla. +edad = ... +print("Mi edad es:", edad) + +# ------ Tarea 2 ------ +# Declara una variable de punto flotante con tu estatura (en metros). +estatura = ... +print("Mi estatura es:", estatura, "m") + +# ------ Tarea 3 ------ +# Declara una variable de texto con tu nombre completo. +nombre = ... +print("Mi nombre es:", nombre) + +# ------ Tarea 4 ------ +# Declara una variable booleana que indique si te gusta Python. +gusta_python = ... +print("¿Me gusta Python?", gusta_python) + +# ------ Tarea 5 ------ +# Usa la función type() para mostrar el tipo de cada variable. +print(type(edad), type(estatura), type(nombre), type(gusta_python)) + +# ------ Tarea 6 ------ +# Convierte la variable 'edad' a float y 'estatura' a int. +# Muestra los resultados. +edad_float = ... +estatura_int = ... +print("Edad como float:", edad_float) +print("Estatura como int:", estatura_int) + + +# ============================================================= +# Ejemplo de solución (descomenta para ver el resultado) +# ============================================================= +# edad = 25 +# estatura = 1.75 +# nombre = "Ana García" +# gusta_python = True +# print(type(edad), type(estatura), type(nombre), type(gusta_python)) +# edad_float = float(edad) +# estatura_int = int(estatura) diff --git a/basico/02_condicionales.py b/basico/02_condicionales.py new file mode 100644 index 0000000..eb1e7b5 --- /dev/null +++ b/basico/02_condicionales.py @@ -0,0 +1,76 @@ +# ============================================================= +# Ejercicio: Condicionales +# Nivel: Básico +# ============================================================= +# Descripción: +# Practica el uso de if / elif / else para tomar decisiones +# en tu programa. +# ============================================================= + +# ------ Tarea 1 ------ +# Escribe un programa que lea un número e indique si es +# positivo, negativo o cero. +numero = int(input("Ingresa un número: ")) + +# Tu código aquí: + + +# ------ Tarea 2 ------ +# Escribe un programa que determine si un número es par o impar. +numero2 = int(input("Ingresa otro número: ")) + +# Tu código aquí (pista: usa el operador %): + + +# ------ Tarea 3 ------ +# Escribe un programa que clasifique una nota (0-100) en: +# - Sobresaliente: 90-100 +# - Notable: 70-89 +# - Aprobado: 50-69 +# - Reprobado: 0-49 +nota = float(input("Ingresa tu nota (0-100): ")) + +# Tu código aquí: + + +# ------ Tarea 4 ------ +# Escribe un programa que determine si un año es bisiesto. +# Un año es bisiesto si es divisible entre 4, excepto los +# siglos, que deben ser divisibles entre 400. +anio = int(input("Ingresa un año: ")) + +# Tu código aquí: + + +# ============================================================= +# Ejemplos de solución +# ============================================================= +# --- Tarea 1 --- +# if numero > 0: +# print("Positivo") +# elif numero < 0: +# print("Negativo") +# else: +# print("Cero") + +# --- Tarea 2 --- +# if numero2 % 2 == 0: +# print("Par") +# else: +# print("Impar") + +# --- Tarea 3 --- +# if nota >= 90: +# print("Sobresaliente") +# elif nota >= 70: +# print("Notable") +# elif nota >= 50: +# print("Aprobado") +# else: +# print("Reprobado") + +# --- Tarea 4 --- +# if (anio % 4 == 0 and anio % 100 != 0) or (anio % 400 == 0): +# print(f"{anio} es bisiesto") +# else: +# print(f"{anio} no es bisiesto") diff --git a/basico/03_bucles.py b/basico/03_bucles.py new file mode 100644 index 0000000..a868c07 --- /dev/null +++ b/basico/03_bucles.py @@ -0,0 +1,82 @@ +# ============================================================= +# Ejercicio: Bucles +# Nivel: Básico +# ============================================================= +# Descripción: +# Practica los bucles for y while para repetir instrucciones. +# ============================================================= + +# ------ Tarea 1 ------ +# Imprime los números del 1 al 20 usando un bucle for. + +# Tu código aquí: + + +# ------ Tarea 2 ------ +# Imprime la tabla de multiplicar de un número dado por el usuario. +n = int(input("¿De qué número quieres la tabla de multiplicar? ")) + +# Tu código aquí: + + +# ------ Tarea 3 ------ +# Suma todos los números del 1 al 100 usando un bucle while. +# Al final muestra el resultado. + +# Tu código aquí: + + +# ------ Tarea 4 ------ +# Pide al usuario que adivine un número secreto (por ejemplo 42). +# El programa debe seguir pidiendo números hasta que el usuario +# acierte, indicando en cada intento si el número es mayor o menor. + +secreto = 42 +# Tu código aquí: + + +# ------ Tarea 5 ------ +# Imprime el triángulo de asteriscos de altura 5: +# * +# ** +# *** +# **** +# ***** + +# Tu código aquí: + + +# ============================================================= +# Ejemplos de solución +# ============================================================= +# --- Tarea 1 --- +# for i in range(1, 21): +# print(i) + +# --- Tarea 2 --- +# for i in range(1, 11): +# print(f"{n} x {i} = {n * i}") + +# --- Tarea 3 --- +# total = 0 +# i = 1 +# while i <= 100: +# total += i +# i += 1 +# print("Suma:", total) # Esperado: 5050 + +# --- Tarea 4 --- +# intento = 0 +# while True: +# intento = int(input("Adivina el número: ")) +# if intento < secreto: +# print("Más alto") +# elif intento > secreto: +# print("Más bajo") +# else: +# print("¡Correcto!") +# break + +# --- Tarea 5 --- +# for i in range(1, 6): +# print("*" * i) diff --git a/basico/04_funciones.py b/basico/04_funciones.py new file mode 100644 index 0000000..f75cb66 --- /dev/null +++ b/basico/04_funciones.py @@ -0,0 +1,94 @@ +# ============================================================= +# Ejercicio: Funciones +# Nivel: Básico +# ============================================================= +# Descripción: +# Practica la definición y el uso de funciones para modularizar +# tu código y reutilizar lógica. +# ============================================================= + +# ------ Tarea 1 ------ +# Define una función que reciba dos números y retorne su suma. +def suma(a, b): + # Tu código aquí: + pass + +print(suma(3, 5)) # Esperado: 8 +print(suma(10, -4)) # Esperado: 6 + + +# ------ Tarea 2 ------ +# Define una función que reciba un número y retorne +# True si es primo, False en caso contrario. +def es_primo(n): + # Tu código aquí: + pass + +print(es_primo(7)) # True +print(es_primo(10)) # False +print(es_primo(2)) # True + + +# ------ Tarea 3 ------ +# Define una función que calcule el factorial de n de forma iterativa. +def factorial(n): + # Tu código aquí: + pass + +print(factorial(5)) # 120 +print(factorial(0)) # 1 +print(factorial(10)) # 3628800 + + +# ------ Tarea 4 ------ +# Define una función con parámetro por defecto que salude a una +# persona. Si no se pasa nombre, debe saludar con "Mundo". +def saludar(nombre="Mundo"): + # Tu código aquí: + pass + +saludar() # "¡Hola, Mundo!" +saludar("Brandon") # "¡Hola, Brandon!" + + +# ------ Tarea 5 ------ +# Define una función que reciba un número variable de argumentos +# y retorne su promedio. +def promedio(*numeros): + # Tu código aquí: + pass + +print(promedio(10, 20, 30)) # 20.0 +print(promedio(5, 5, 5, 5, 5)) # 5.0 + + +# ============================================================= +# Ejemplos de solución +# ============================================================= +# --- Tarea 1 --- +# def suma(a, b): +# return a + b + +# --- Tarea 2 --- +# def es_primo(n): +# if n < 2: +# return False +# for i in range(2, int(n**0.5) + 1): +# if n % i == 0: +# return False +# return True + +# --- Tarea 3 --- +# def factorial(n): +# resultado = 1 +# for i in range(2, n + 1): +# resultado *= i +# return resultado + +# --- Tarea 4 --- +# def saludar(nombre="Mundo"): +# print(f"¡Hola, {nombre}!") + +# --- Tarea 5 --- +# def promedio(*numeros): +# return sum(numeros) / len(numeros) diff --git a/basico/05_listas.py b/basico/05_listas.py new file mode 100644 index 0000000..80cb7df --- /dev/null +++ b/basico/05_listas.py @@ -0,0 +1,89 @@ +# ============================================================= +# Ejercicio: Listas +# Nivel: Básico +# ============================================================= +# Descripción: +# Practica la creación, acceso y manipulación de listas. +# ============================================================= + +# ------ Tarea 1 ------ +# Crea una lista con los nombres de 5 frutas y muéstrala. +frutas = [...] +print(frutas) + +# Accede e imprime la primera y la última fruta. +primera = ... +ultima = ... +print(primera, ultima) + + +# ------ Tarea 2 ------ +# Dado el siguiente listado de números, agrega el número 99 al +# final, inserta el número 0 al inicio y elimina el número 5. +numeros = [1, 2, 3, 4, 5, 6, 7, 8] + +# Tu código aquí: + +print(numeros) # [0, 1, 2, 3, 4, 6, 7, 8, 99] + + +# ------ Tarea 3 ------ +# Sin usar la función sorted(), ordena la siguiente lista de menor +# a mayor usando el método .sort() y luego inviértela. +desordenada = [34, 7, 23, 32, 5, 62] + +# Tu código aquí: + +print(desordenada) # Ordenada ascendente +# luego invertida + + +# ------ Tarea 4 ------ +# Dada la lista, calcula y muestra: máximo, mínimo y promedio. +valores = [10, 45, 3, 78, 22, 56, 14] + +maximo = ... +minimo = ... +promedio = ... +print(f"Máx: {maximo}, Mín: {minimo}, Promedio: {promedio:.2f}") + + +# ------ Tarea 5 ------ +# Crea una nueva lista que contenga solo los números pares +# de la siguiente lista, usando un bucle for. +todos = list(range(1, 21)) +pares = [] + +# Tu código aquí: + +print(pares) # [2, 4, 6, 8, 10, 12, 14, 16, 18, 20] + + +# ============================================================= +# Ejemplos de solución +# ============================================================= +# --- Tarea 1 --- +# frutas = ["manzana", "banana", "cereza", "durazno", "uva"] +# primera = frutas[0] +# ultima = frutas[-1] + +# --- Tarea 2 --- +# numeros.append(99) +# numeros.insert(0, 0) +# numeros.remove(5) + +# --- Tarea 3 --- +# desordenada.sort() +# print(desordenada) +# desordenada.reverse() +# print(desordenada) + +# --- Tarea 4 --- +# maximo = max(valores) +# minimo = min(valores) +# promedio = sum(valores) / len(valores) + +# --- Tarea 5 --- +# for n in todos: +# if n % 2 == 0: +# pares.append(n) diff --git a/intermedio/01_diccionarios_y_conjuntos.py b/intermedio/01_diccionarios_y_conjuntos.py new file mode 100644 index 0000000..79cc0d3 --- /dev/null +++ b/intermedio/01_diccionarios_y_conjuntos.py @@ -0,0 +1,87 @@ +# ============================================================= +# Ejercicio: Diccionarios y conjuntos +# Nivel: Intermedio +# ============================================================= +# Descripción: +# Practica el uso de diccionarios (dict) y conjuntos (set) +# para almacenar y consultar datos estructurados. +# ============================================================= + +# ------ Tarea 1 ------ +# Crea un diccionario que represente a un estudiante con las +# claves: nombre, edad, carrera y promedio. +estudiante = { + # Tu código aquí +} +print(estudiante) + +# Accede e imprime solo el nombre y el promedio. +print(estudiante["nombre"], estudiante["promedio"]) + + +# ------ Tarea 2 ------ +# Dado el siguiente diccionario de precios, actualiza el precio +# de "leche" a 25, agrega "mantequilla": 50 y elimina "pan". +precios = {"leche": 18, "huevos": 30, "pan": 22, "azucar": 15} + +# Tu código aquí: + +print(precios) + + +# ------ Tarea 3 ------ +# Itera sobre el diccionario de precios e imprime cada producto +# con su precio en formato: "Producto: X - Precio: $Y" + +# Tu código aquí: + + +# ------ Tarea 4 ------ +# Dado el siguiente texto, cuenta la frecuencia de cada palabra +# usando un diccionario. +texto = "el gato y el perro y el pajaro y el gato" + +frecuencia = {} +# Tu código aquí: + +print(frecuencia) +# Esperado (orden puede variar): +# {'el': 4, 'gato': 2, 'y': 3, 'perro': 1, 'pajaro': 1} + + +# ------ Tarea 5 ------ +# Usando conjuntos, encuentra los elementos comunes y los +# exclusivos entre las dos listas siguientes. +lista_a = [1, 2, 3, 4, 5, 6] +lista_b = [4, 5, 6, 7, 8, 9] + +comunes = ... # {4, 5, 6} +solo_en_a = ... # {1, 2, 3} +solo_en_b = ... # {7, 8, 9} +print(comunes, solo_en_a, solo_en_b) + + +# ============================================================= +# Ejemplos de solución +# ============================================================= +# --- Tarea 1 --- +# estudiante = {"nombre": "Ana", "edad": 21, "carrera": "Sistemas", "promedio": 8.9} + +# --- Tarea 2 --- +# precios["leche"] = 25 +# precios["mantequilla"] = 50 +# del precios["pan"] + +# --- Tarea 3 --- +# for producto, precio in precios.items(): +# print(f"Producto: {producto} - Precio: ${precio}") + +# --- Tarea 4 --- +# for palabra in texto.split(): +# frecuencia[palabra] = frecuencia.get(palabra, 0) + 1 + +# --- Tarea 5 --- +# set_a, set_b = set(lista_a), set(lista_b) +# comunes = set_a & set_b +# solo_en_a = set_a - set_b +# solo_en_b = set_b - set_a diff --git a/intermedio/02_funciones_orden_superior.py b/intermedio/02_funciones_orden_superior.py new file mode 100644 index 0000000..0d54fdd --- /dev/null +++ b/intermedio/02_funciones_orden_superior.py @@ -0,0 +1,86 @@ +# ============================================================= +# Ejercicio: Funciones de orden superior +# Nivel: Intermedio +# ============================================================= +# Descripción: +# Practica el uso de funciones lambda, map(), filter() y +# reduce() para escribir código más conciso y funcional. +# ============================================================= + +from functools import reduce + +# ------ Tarea 1 ------ +# Usa map() para obtener una lista con el cuadrado de cada +# número en la siguiente lista. +numeros = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] + +cuadrados = list(map(..., numeros)) +print(cuadrados) +# Esperado: [1, 4, 9, 16, 25, 36, 49, 64, 81, 100] + + +# ------ Tarea 2 ------ +# Usa filter() para obtener solo los números impares de la lista. +impares = list(filter(..., numeros)) +print(impares) +# Esperado: [1, 3, 5, 7, 9] + + +# ------ Tarea 3 ------ +# Usa reduce() para calcular el producto de todos los números +# en la lista [1, 2, 3, 4, 5]. +producto = reduce(..., [1, 2, 3, 4, 5]) +print(producto) +# Esperado: 120 + + +# ------ Tarea 4 ------ +# Ordena la siguiente lista de tuplas por el segundo elemento +# usando una lambda como key. +pares = [(1, 'banana'), (2, 'apple'), (3, 'cherry')] + +ordenados = sorted(pares, key=...) +print(ordenados) +# Esperado: [(2, 'apple'), (1, 'banana'), (3, 'cherry')] + + +# ------ Tarea 5 ------ +# Crea una función 'aplicar' que reciba una función y una lista, +# y retorne una nueva lista con la función aplicada a cada elemento. +def aplicar(func, lista): + # Tu código aquí: + pass + +doble = aplicar(lambda x: x * 2, [1, 2, 3, 4]) +print(doble) # [2, 4, 6, 8] + + +# ------ Tarea 6 ------ +# Encadena map y filter: obtén los cuadrados de los números +# pares en el rango 1-20. +resultado = list(map(..., filter(..., range(1, 21)))) +print(resultado) +# Esperado: [4, 16, 36, 64, 100, 144, 196, 256, 324, 400] + + +# ============================================================= +# Ejemplos de solución +# ============================================================= +# --- Tarea 1 --- +# cuadrados = list(map(lambda x: x ** 2, numeros)) + +# --- Tarea 2 --- +# impares = list(filter(lambda x: x % 2 != 0, numeros)) + +# --- Tarea 3 --- +# producto = reduce(lambda a, b: a * b, [1, 2, 3, 4, 5]) + +# --- Tarea 4 --- +# ordenados = sorted(pares, key=lambda t: t[1]) + +# --- Tarea 5 --- +# def aplicar(func, lista): +# return list(map(func, lista)) + +# --- Tarea 6 --- +# resultado = list(map(lambda x: x ** 2, filter(lambda x: x % 2 == 0, range(1, 21)))) diff --git a/intermedio/03_comprensiones.py b/intermedio/03_comprensiones.py new file mode 100644 index 0000000..5843ce7 --- /dev/null +++ b/intermedio/03_comprensiones.py @@ -0,0 +1,80 @@ +# ============================================================= +# Ejercicio: Comprensiones de listas, diccionarios y conjuntos +# Nivel: Intermedio +# ============================================================= +# Descripción: +# Las comprensiones (comprehensions) permiten crear colecciones +# de forma compacta y legible. +# Sintaxis básica: [expresión for elemento in iterable if condición] +# ============================================================= + +# ------ Tarea 1 ------ +# Usando una comprensión de lista, crea una lista con los cubos +# de los números del 1 al 10. +cubos = [...] +print(cubos) +# Esperado: [1, 8, 27, 64, 125, 216, 343, 512, 729, 1000] + + +# ------ Tarea 2 ------ +# Usando una comprensión de lista, filtra y convierte a mayúsculas +# solo las palabras con más de 4 caracteres. +palabras = ["hola", "mundo", "python", "es", "genial", "hoy"] +largas = [...] +print(largas) +# Esperado: ['MUNDO', 'PYTHON', 'GENIAL'] + + +# ------ Tarea 3 ------ +# Crea un diccionario que mapee cada número del 1 al 5 con +# su cuadrado usando una comprensión de diccionario. +cuadrados_dict = {...} +print(cuadrados_dict) +# Esperado: {1: 1, 2: 4, 3: 9, 4: 16, 5: 25} + + +# ------ Tarea 4 ------ +# Crea un conjunto con las letras únicas (sin espacios) de la +# siguiente frase usando una comprensión de conjunto. +frase = "comprensiones en python" +letras = {...} +print(letras) # Conjunto de letras únicas + + +# ------ Tarea 5 ------ +# "Aplanar" (flatten) una lista de listas usando una comprensión +# de lista anidada. +matriz = [[1, 2, 3], [4, 5, 6], [7, 8, 9]] +plana = [...] +print(plana) +# Esperado: [1, 2, 3, 4, 5, 6, 7, 8, 9] + + +# ------ Tarea 6 ------ +# Usando comprensiones, crea una lista de pares (x, y) donde +# x e y van de 0 a 3 y x != y. +pares = [...] +print(pares) +# Esperado: [(0,1),(0,2),(0,3),(1,0),(1,2),(1,3),(2,0),(2,1),(2,3),(3,0),(3,1),(3,2)] + + +# ============================================================= +# Ejemplos de solución +# ============================================================= +# --- Tarea 1 --- +# cubos = [x ** 3 for x in range(1, 11)] + +# --- Tarea 2 --- +# largas = [p.upper() for p in palabras if len(p) > 4] + +# --- Tarea 3 --- +# cuadrados_dict = {n: n ** 2 for n in range(1, 6)} + +# --- Tarea 4 --- +# letras = {c for c in frase if c != ' '} + +# --- Tarea 5 --- +# plana = [num for fila in matriz for num in fila] + +# --- Tarea 6 --- +# pares = [(x, y) for x in range(4) for y in range(4) if x != y] diff --git a/intermedio/04_archivos_y_excepciones.py b/intermedio/04_archivos_y_excepciones.py new file mode 100644 index 0000000..6c0038b --- /dev/null +++ b/intermedio/04_archivos_y_excepciones.py @@ -0,0 +1,105 @@ +# ============================================================= +# Ejercicio: Manejo de archivos y excepciones +# Nivel: Intermedio +# ============================================================= +# Descripción: +# Practica la lectura/escritura de archivos con open() y +# el manejo de errores con try/except/finally. +# ============================================================= + +import os + +# ------ Tarea 1 ------ +# Escribe una función que cree un archivo llamado "notas.txt" +# con tres líneas de texto (las que tú quieras). +def crear_archivo(nombre_archivo): + # Tu código aquí (usa 'with open(...)'): + pass + +crear_archivo("notas.txt") + + +# ------ Tarea 2 ------ +# Escribe una función que lea el contenido del archivo +# y lo imprima línea a línea con su número de línea. +def leer_archivo(nombre_archivo): + # Tu código aquí: + pass + +leer_archivo("notas.txt") + + +# ------ Tarea 3 ------ +# Escribe una función que añada (sin sobreescribir) una nueva +# línea al final del archivo. +def agregar_linea(nombre_archivo, linea): + # Tu código aquí (usa modo 'a'): + pass + +agregar_linea("notas.txt", "Línea agregada al final") +leer_archivo("notas.txt") + + +# ------ Tarea 4 ------ +# Escribe una función que intente abrir un archivo y maneje +# el error FileNotFoundError mostrando un mensaje amigable. +def abrir_seguro(nombre_archivo): + # Tu código aquí: + pass + +abrir_seguro("archivo_inexistente.txt") +abrir_seguro("notas.txt") + + +# ------ Tarea 5 ------ +# Escribe una función que convierta un string a entero de forma +# segura, retornando None si la conversión falla. +def convertir_a_entero(valor): + # Tu código aquí: + pass + +print(convertir_a_entero("42")) # 42 +print(convertir_a_entero("hola")) # None +print(convertir_a_entero("3.14")) # None (no es entero directo) + + +# Limpieza del archivo de prueba +if os.path.exists("notas.txt"): + os.remove("notas.txt") + + +# ============================================================= +# Ejemplos de solución +# ============================================================= +# --- Tarea 1 --- +# def crear_archivo(nombre_archivo): +# with open(nombre_archivo, "w", encoding="utf-8") as f: +# f.write("Primera nota\n") +# f.write("Segunda nota\n") +# f.write("Tercera nota\n") + +# --- Tarea 2 --- +# def leer_archivo(nombre_archivo): +# with open(nombre_archivo, "r", encoding="utf-8") as f: +# for i, linea in enumerate(f, start=1): +# print(f"{i}: {linea}", end="") + +# --- Tarea 3 --- +# def agregar_linea(nombre_archivo, linea): +# with open(nombre_archivo, "a", encoding="utf-8") as f: +# f.write(linea + "\n") + +# --- Tarea 4 --- +# def abrir_seguro(nombre_archivo): +# try: +# with open(nombre_archivo, "r", encoding="utf-8") as f: +# print(f.read()) +# except FileNotFoundError: +# print(f"Error: el archivo '{nombre_archivo}' no existe.") + +# --- Tarea 5 --- +# def convertir_a_entero(valor): +# try: +# return int(valor) +# except (ValueError, TypeError): +# return None