Mostrando entradas con la etiqueta Colecciones de datos. Mostrar todas las entradas
Mostrando entradas con la etiqueta Colecciones de datos. Mostrar todas las entradas

jueves, 5 de marzo de 2026

DATOS. Acceso a datos

CSV. Datos estructurados (III)

Acceso y descarga de csv

Vamos a centrarnos en este script en el trabajo con un archivo .csv, pensando no en el acceso (tema ya tratado en esta entrada), sino en tener disponible su contendio desde el script. Eso sí, seguiremos usando el módulo propio CSV, si bien ahora en la opción de diccionario.

Para que se entienda mejor el proceso a seguir, empezaremos por el acceso al archivo .csv. La diferencia principal respecto al script parejo de la entrada anterior es que sustituímos lector = csv.reader(archivo, delimiter=',') por lector_dict = csv.DictReader(archivo). El resto derivan de ésta.



import csv

archivo_nombre = 'datos/datos.csv'										# 1. Definimos la ruta del archivo

try:
    with open(archivo_nombre, mode='r', encoding='utf-8') as archivo:  # 2. Abrimos el archivo en modo lectura ('r')
        lector_dict = csv.DictReader(archivo)                          # 3. Creamos el lector de diccionarios
        print(f"Leyendo datos de: {archivo_nombre}\n" + "-"*30)
        for fila in lector_dict:                                       # 4. Recorremos cada fila (cada fila es un diccionario)
            nombre = fila['Nombre']                                                         
            edad = fila['Edad']        
            print(f"Usuario: {nombre} | Edad: {edad}")                          

except FileNotFoundError:                                              #Control de errores
    print(f"Error: El archivo '{archivo_nombre}' no existe.")
except KeyError as e:
    print(f"Error: No se encontró la columna {e} en el archivo.")


A pesar de las diferencias, ambos archivo comparten la misma limitación: la base de datos sólo está disponible dentro del ámbito de with open(), pero fuera no podemos acceder a los datos, así que si nos interesa deberemos trasladarlos a una colección de datos del propio script, concretamente a una lista de diccionarios.



import csv

archivo_nombre = 'datos/datos.csv'                                                  # 1. Definimos la ruta del archivo

datos_internos = []                                                                 # Lista para almacenar la base de datos en memoria


try:
    with open(archivo_nombre, mode='r', encoding='utf-8') as archivo:  				# 2. Abrimos el archivo en modo lectura ('r')
        lector_dict = csv.DictReader(archivo)                                       # 3. Creamos el lector de diccionarios
        print(f"Leyendo datos de: {archivo_nombre}\n" + "-"*30)
        for fila in lector_dict:                                                    # 4. Recorremos cada fila (que es un diccionario)
            nombre = fila['Nombre']                                                         
            edad = int(fila['Edad'])
            datos_internos.append(fila)        
            print(f"Usuario: {nombre} | Edad: {edad}")                          
        print(f"--- Carga finalizada ---")
        print(f"Se han almacenado {len(datos_internos)} registros en el diccionario interno.")

    if datos_internos:																# Ejemplo: Acceder al primer registro almacenado
        primero = datos_internos[0]
        print(f"Primer registro en memoria: {primero['Nombre']} tiene {primero['Edad']} años.")
        
except FileNotFoundError:                                                           #Control de errores
    print(f"Error: El archivo '{archivo_nombre}' no existe.")
except KeyError as e:
    print(f"Error: No se encontró la columna {e} en el archivo.")

#Ejemplo de acceso a la estructura del diccionario ---------------------------------------------------------------------------------------

registro_ejemplo = datos_internos[0]                   # Tomamos el primer diccionario de nuestra lista para el ejemplo
print(f"Claves: {list(registro_ejemplo.keys())}")      # A. Identificar solo las CLAVES
print(f"Valores: {list(registro_ejemplo.values())}")   # B. Identificar solo los VALORES


Lo que nos permite importar al script el contenido del archivo .csv empieza aquí (datos_internos = []) y se concreta en estas dos líneas:
  • for fila in lector_dict: ----> Recorre el archivo .csv
  • ----datos_internos.append(fila) ----> Añade contenido a la lista (de diccionarios) datos_internos

Ellas hacen posible el correcto acceso a los datos mediante instrucciones como print(f"Claves: {list(registro_ejemplo.keys())}"), que muestra las claves del diccionario.

Cierto que la consecuencia es un incremento de la carga de memoria, pero la ventaja en rapidez de funcionamiento compensa cuando necesitamos realizar diferentes acciones sobre los datos desde un mismo script. Tal es el caso del que sigue y con el que finalizamos esta entrada: un script mediante el que accedemos a una base de datos, la cargamos en memoria y realizamso sobre ella un conjunto de acciones que aquí se concretan en seleccionar y filtrar registros.



import csv

# --- FASE 1: CARGA DE DATOS  ---------------------------------------------------

ruta_archivo = 'datos/datos.csv'
datos_internos = []

try:
    with open(ruta_archivo, mode='r', encoding='utf-8') as archivo:
        lector = csv.DictReader(archivo)
        for fila in lector:
            fila['Edad'] = int(fila['Edad']) # Convertimos el valor de [Edad] a entero para poder filtrar
            datos_internos.append(fila)
    print(f"Sistema listo. {len(datos_internos)} registros cargados.\n")

except FileNotFoundError:
    print("Error: No se encontró el archivo en D:/. Por favor, créalo primero.")
    exit() # Finaliza el script si no hay datos

# --- FASE 2: OPCIONES ------------------------------------------------------------

while True:
    print("\n===============================")
    print("   GESTOR DE CONSULTAS")
    print("===============================")
    print("1. Buscar por NOMBRE (Coincidencia parcial)")
    print("2. Filtrar por EDAD (Exacta o Rango)")
    print("3. Salir")
    
    opcion = input("\nSeleccione una opción: ").strip()

    if opcion == '3':
        print("Saliendo del sistema...")
        break

# --- OPCIÓN 1: BÚSQUEDA POR NOMBRE ---
    if opcion == '1':
        termino = input("Escriba el nombre o parte de él: ").strip().lower()
        encontrados = [r for r in datos_internos if termino in r['Nombre'].lower()]
        
        print(f"\nResultados para '{termino}':")
        if encontrados:
            for e in encontrados:
                print(f"ID: {e['Nombre']} | Edad: {e['Edad']}")
        else:
            print("No se encontraron coincidencias.")

# --- OPCIÓN 2: FILTRO POR EDAD ---
    elif opcion == '2':
        print("\n--- Filtro de Edad ---")
        print("A. Edad exacta")
        print("B. Rango (Mínimo y Máximo)")
        sub = input("Elija modalidad (A/B): ").strip().upper()

        resultados = []
        try:
            if sub == 'A':
                objetivo = int(input("Edad a buscar: "))
                resultados = [r for r in datos_internos if r['Edad'] == objetivo]  # Identificamos si el valor de la clave 'Edad' coincide
            
            elif sub == 'B':
                v_min = int(input("Edad mínima: "))
                v_max = int(input("Edad máxima: "))
                resultados = [r for r in datos_internos if v_min <= r['Edad'] <= v_max]  # Filtro por intervalo de valores          
         
            if resultados:
                print(f"\nSe hallaron {len(resultados)} personas:")
                for r in resultados:
                    print(f"• {r['Nombre']} - {r['Edad']} años")
            else:
                print("No hay registros en ese rango.")
                
        except ValueError:
            print("Error: Por favor, ingrese solo números enteros para la edad.")

    else:
        print("Opción no válida. Por favor, marque 1, 2 o 3.")

print("\nPrograma finalizado correctamente.")


NOTA: El archivo .csv de prueba es necesario para el correcto funcionamiento de estos tres script, aunque siempre los puedes adaptar para que funcionen con un .csv diferente. No obstante, si prefieren no hacerlo, aquí lo puedes descargar.

miércoles, 11 de febrero de 2026

Python

Logo de Python


Usos prácticos de listas (1)


Sabemos qué es una lista en Python y cómo podemos usarla, pero nos interesa conocer xómo y para qué podemos usarlas en la práctica. Una de estas utilidades será el tema de esta entrada, concretamente su uso como soporte para la recopilación de datos.

Dado que las listas permiten incluir diferentes tipos de datos, que los datos estén repetidos y que sea posoble modificarlos, estas colecciones son muy útiles para situaciones en las que tenemos que recopilar datos de distintos tipos y además desconocemos cuantos.

Un ejemplo de ello es cuando introducimos por teclado los resultados de la aplicación de una prueba grupal. En este caso tenemos datos de distinto tipo (string para nombres, datos en formato fecha, valores numéricos que se pueden repetir...) y no sabemos a priori de cuantos datos estamos hablando, ya que unos alumnos pueden haber resulto n ejercicios y otros n+/x.

En estas condiciones, podemos empezar declarando una lista vacía y después darle contenido desde teclado mediante un bucle. Una vez cumplimentado el "registro" procedemos a almacenarlo en un archivo a modo de base de datos.

Vamos a pedirle a Gemini que genere un script que cumpla estos objetivos y a analizar el modo en que plantea el uso de la lista.



import os

def registrar_evaluacion_continua():
    nombre_archivo = "base_datos_alumnos.txt"

    # Si el archivo no existe, creamos la cabecera para identificar columnas
    if not os.path.exists(nombre_archivo):
        with open(nombre_archivo, "w", encoding="utf-8") as f:
            headers = ["Nombre", "Apellidos", "Edad", "Curso"]
            items_headers = [f"Item_{i:02d}" for i in range(1, 31)]
            f.write(",".join(headers + items_headers + ["PD"]) + "\n")

    while True:
        print("\n" + "="*40)
        # 1. Recogida de identificación
        nombre = input("Nombre: ")
        apellidos = input("Apellidos: ")
        edad = input("Edad: ")
        curso = input("Curso (1º a 6º EP): ")

        # Iniciamos lista: [Nombre, Apellidos, Edad, Curso]
        sujeto_datos = [nombre, apellidos, edad, curso]

        aciertos = 0
        finalizado_por_tiempo = False

        print(f"\nIntroduzca resultados para {nombre} (1:Acierto, 0:Fallo, Enter:Fin tiempo)")

        # 2. Bucle de 30 ítems
        for i in range(1, 31):
            if not finalizado_por_tiempo:
                res = input(f"Ítem {i:02d}: ").strip()
                if res == "":
                    finalizado_por_tiempo = True
                    sujeto_datos.append("") # Celda vacía para el resto
                else:
                    sujeto_datos.append(res)
                    if res == "1":
                        aciertos += 1
            else:
                sujeto_datos.append("") # Relleno por no finalizado

        # 3. Añadir Puntuación Directa (PD) al final
        sujeto_datos.append(str(aciertos))

        # Feedback inmediato al usuario
        print(f"\n>>> REGISTRO FINALIZADO: {nombre} {apellidos}")
        print(f">>> Puntuación Directa obtenida: {aciertos}")

        # 4. Guardado persistente (Modo 'a' para no borrar sesiones previas)
        with open(nombre_archivo, "a", encoding="utf-8") as f:
            f.write(",".join(sujeto_datos) + "\n")

        # Opción de cerrar el script tras este alumno
        if input("\n¿Desea registrar a otro alumno ahora? (s/n): ").lower() != 's':
            break

    print(f"\n[SISTEMA] Datos sincronizados en '{nombre_archivo}'.")

if __name__ == "__main__":
    registrar_evaluacion_continua()


Este script funciona correctamente en local (trasladándolo al IDE) y se ajusta a lo solicitado al bot, aunque fue necesario ir puliendo la demanda hasta conseguirlo.

El problema, no obstante, es que no nos ayuda a entender y a aprender. Resuelve la tarea según unos parámetros que no quedan explicitados y que son corregidos cuando se le requiere, aunque tampoco se explica porqué no hizo antes lo que ahora es necesario, pero reincide en una propuesta que se aleja del modo "didáctico" en que queremos que lo haga para, ajustándose al nuestro actual nivel de complejidad en la demanda, facilite nuestro proceso de aprendizaje: su meta es fundamentalmente la eficiencia, resolver el problema.

Para lograr esto es necesario:

  • Subdivir la tarea paso a paso.
  • Pedir al chatbot que ejecute esa construcción secuencial del script.
  • Realizar sobre esas propuestas las modificaciones que consideremos pertinente.

De este modo es posible alcanzar nuestro objetivo, que es comprender el script antes que conseguir que funcione.Y todo ello en relación con nuestro objetivo inicial: el uso práctico de una lista como recurso para recopilar datos.

Desarrollaremos este procedimiento en entradas próximas. Dada su complejidad y el tiempo que requiere para su desarrollo, por el momento será suficiente con presentarlo.

martes, 3 de febrero de 2026

Python.


Listas. 
Manejo básico

Las listas son las colecciones nativas de datos más simples y flexibles con las que cuenta Python, lo que hace que sean usadas con mucha frecuencia.


Como dije [en su presentación], una lista es una colección ordenada y mutables de datos. Además los datos pueden ser de diferentes tipos (caracteres, cadenas, enteros, reales, booleanos) y pueden estar repetidos. Esto, junto con las operaciones permitidas sobre ella, la convierten en un recurso muy flexible.

En este cuaderno cómo trabajar con listas.


lunes, 2 de febrero de 2026

Python


Colecciones de datos nativas


Además de las variables, Python también permite trabajar con colecciones de datos. En el lenguaje-base están disponibles cuatro colecciones de datos, pero mediante bibliotecas complementarias podemos ampliar esta tipología básica. De momento, en esta entrada, nos limitaremos a presentar las colecciones nativas.

Empecemos por un breve resumen que nos ofrece Gemini a modo de síntesis.

ColecciónOrdenadaMutableDatos duplicados
Lista
TuplaNo
Conjunto (set)NoNo
DiccionarioClaves no, valores sí
En esta entrada, que hace de presentación, vamos a explicar brevemente cada una de ellas. En [este enlace] puedes acceder a la información que ofrece la página oficial de Python y en entradas posteriores trataremos cada una de ellas de forma más detallada y por separado.

Listas (list). Son colecciones ordenadas y mutables que permiten incluir datos duplicados. Son la mejor opción cuando necesitas trabajar con una secuencia de elementos ordenados y que se van a modificar frecuentemente.

A nivel de sintaxis se caracterizan por estar delimitadas por corchetes (mi_lista = [1, "hola", 3.14])

Tuplas (tuple). Son colecciones ordenadas e inmutables, lo que implica que no se pueden cambiar una vez creadas, lo que las hace más rápidas y seguras para datos que no deben variar.

A nivel sintáctico se presentan delimitadas por paréntesis (mi_tupla = (10, 20, 30))

Conjuntos (set). Son colecciones desordenadas y no indexadas. Su característica principal es que no permiten duplicados. 

Admite el cambio de datos, pero sólo en el sentido de que es posible añadir o quitar elementos siempre que estos, a su vez, sean inmutable, pero no elementos mutables. Esto implica que podemos añadir números, cadenas o tuplas (que son inmutables), pero no listas (que son mutables).

Son muy eficientes para operaciones matemáticas como uniones o intersecciones de conjuntos. Si convertimos una lista en un conjunto se eliminarán los elementos repetidos que podía contener la lista, lo que permite plantear procedimientos interesantes; uno de ellos es la verificación de la pertenencia de un dato a un conjunto.

Su sintaxis (mi_set = {1, 2, 3, 3}) es el uso de las llaves como delimitador.

Diccionarios (dict). Son colecciones de pares clave-valor, extremadamente rápidos para buscar información conociendo la clave. Su uso es interesante para representar objetos (POO) y para trabajar con bases de datos en memoria o en mapeos.

Se identifican sintácticamente por estar delimitados por llaves (mi_dict = {"nombre": "Ana", "edad": 25}) junto con la estructura llave:valor.

viernes, 16 de mayo de 2025

Python. Lenguaje.

Listas y tuplas.
Operadores


Los operadores son, [según sabemos], componentes de todo lenguaje de programación que permiten manipular los datos referenciados en las variables de diferentes maneras, según el tipo de operador y de datos de que se trate. También las colecciones de datos admiten la acción de operadores y listas y tuplas comparten los mismos.



Los operadores disponibles en listas y tuplas son los siguientes:
  • :, que permite obtener segmentos del contenido de ambas colecciones.
  • + y *, que permiten realizar las operaciones sobre listas y tuplas. Veremos cuáles.
  • in / not in, que permiten verificar la presencia / no presencia de determinado dato dentro del conjunto.
  • Y los operadores relacionales <, <=, >, >=, == y !=, cuyas funciones describiremos en su momento.
Aunque figure en primer lugar, no trataré el operador : en esta entrada, dada la relación que mantiene con el acceso a los datos. Por este motivo desplazo su análisis a la [entrada correspondiente]

Inicio este análisis con los operadores + y , los cuales cumplen funciones específicas con listas y tuplas, diferentes de las que permiten hacer con variables. 
  • El operador + permite la unión o concatenación de los elementos de varias listas , como cabe suponer por lo que sabemos de los operaciones aritméticos, nos permiten realizar operaciones de suma y multiplicación con listas y tuplas.
lista1 = list([1,2,3,4])
lista2 = list([5,6,7,8])
print(lista1 + lista2) -> devuelve [1,2,3,4,5,6,7,8]

  • Este mismo operador, aplicado a tuplas funciona exactamente igual, aunque lógicamente devuelve una tupla ((1,2,3,4,5,6,7,8))
  • La operación * tiene como efecto la repetición de la lista o la tupla sujeta a tal operación, siendo indiferente que el operador se sitúa antes o después de la lista o tupla. Así que print(3 * lista1) devuelve [1,2,3,4,1,2,3,4,1,2,3,4] y print(tupla1 * 2) devuelve (1,2,3,4,1,2,3,4). En ambos casos el número debe ser entero (ni 3.1 ni 2.4 se admiten como "multiplicadores")
  • Ambos operadores tienen el mismo efecto con independencia de la naturaleza de los elementos de la lista o de la tupla.
  • En ambos casos no está permitido el trabajo con listas y tuplas simultáneamente. No es posible ni lista + tupla, ni tupla * lista, ni ninguna otra combinación o permutación de elementos.
Los operadores in / not in permiten identificar si un datos forma parte o no de una lista o de una tupla. in y not in devuelven el booleano True o False según el resultado de la operación. Ejemplos para lista1 y tupla1 anteriores:

print(5 in lista1) devuelve False
print(1 in lista1) devuelve False

print(5 not in lista1) devuelve True
print(1 not in lista1) devuelve True

print(5 in tupla1) devuelve False
print(1 in tupla1) devuelve False

print(5 not in tupla1) devuelve True
print(1 not in tupla1) devuelve True

Los operadores relacionales permiten comparar dos listas entre sí, elemento a elemento y según criterios específicos en función del tipo de elemento. También devuelven True o False, según el resultado de la comparación. Veamos algunas comparaciones, tomando como referencia las listas y las tuplas creadas antes. Dada la multiplicidad de opciones me limitaré a unos pocos ejemplos, aunque los resultados se pueden hacer extensibles al resto de los operadores:

#Operadores relacionales con listas

print(lista1 == lista1) devuelve True

print(lista1 != lista2) Devuelve True

#Operadores relacionales con tuplas

print(tupla1 == tupla1) Devuelve True

print(tupla1 != tupla2) Devuelve True

#Operadores relacionales con listas y tuplas

print('Operadores relacionales con listas y tuplas')

print(lista1 == tupla1) Devuelve False por ser una lista y la otra tupla, aunque su contenido es el mismo (valores enteros 1,2,3,4 en ambos casos)