Saltar al contenido

Indice / Practicas / EJ-1.1

EJ-1.1 · Directorio de contactos validado

Practica de: 1.3 CSV con el modulo csvDificultad: B

La primera práctica del curso, y la única que se resuelve entera con la biblioteca estándar. Cuarenta contactos, seis que no sirven, y un archivo que explica por qué.

Qué hay que hacer

A partir de contactos_origen.csv (40 filas), producir dos archivos:

Sin pandas. csv.DictReader para leer, csv.DictWriter para escribir, y una decisión por fila.

ELI5Explicado facil

Es la portería de un edificio. Entra quien tiene nombre, timbre y teléfono; el que no, no entra - y queda anotado en el libro, con el motivo.

Lo importante no es la lista de los que entraron: es que el libro exista. Sin él, nadie puede saber después si faltó alguien.

Archivos

Lo que hace interesante al ejercicio

Las cuarenta filas se leen sin un solo error. Ninguna excepción, ningún ValueError: los seis defectos están todos en la capa 3 y en la capa 4 de la lección 1.5, así que hay que buscarlos a propósito.

Y uno de los seis solo se puede detectar recordando lo que ya viste: el correo elena.escobar@example.com aparece en la fila 8 y otra vez en la 13. Mirando una fila sola, las dos son perfectas.

Cómo saber si te salió

python comparar.py mi_validos.csv contactos_validos.csv
python comparar.py mi_rechazados.csv contactos_rechazados.csv

Si no dice nada, tu archivo es idéntico al esperado. Si difiere, te dice qué fila y qué columna. No hay nota ni entrega: es para vos.

Antes de arrancar, mirá los datos

contactos_origen.csv (entrada) · 40 filas, se muestran 5
nombrecorreotelefonociudad
Guadalupe Vegaguadalupe.vega@example.com+54 11 5555-0895San Juan
José Juárezjose.juarez@example.com+54 11 5555-0218San Juan
Yamila Cabrerayamila.cabrera@example.com+54 11 5555-0121Bahía Blanca
Nicolás Escobarnicolas.escobar@example.com+54 11 5555-0547Rosario
Marta Torresvacio+54 11 5555-0798Córdoba

El contrato de salida

contactos_validos.csv · 34 filas

ColumnaTipoQue lleva
nombretextoEl nombre tal cual vino, sin espacios en los extremos
correotextoEl correo en minusculas y sin espacios en los extremos
telefonotextoEl telefono tal cual vino, sin espacios en los extremos
ciudadtextoLa ciudad tal cual vino, sin espacios en los extremos

Orden de las filas: correo ascendente. Despues de descartar el duplicado, correo es unico en la salida, asi que el orden es total y no hace falta desempate. Indice: no se escribe: csv.DictWriter no agrega ninguna columna de indice, y con pandas seria to_csv(index=False)

contactos_rechazados.csv · 6 filas

ColumnaTipoQue lleva
filaenteroNumero de registro en el archivo de entrada, empezando en 1. La cabecera NO cuenta
columnatextoLa columna donde se detecto el defecto
motivotextoUno de: ausente, restriccion_violada, duplicado
valortextoEl valor que causo el rechazo, tal cual vino en el archivo y sin espacios en los extremos. Si la celda estaba vacia, el campo queda vacio

Orden de las filas: fila ascendente. Cada fila de entrada se rechaza a lo sumo una vez, asi que fila es unico en la salida. Indice: no se escribe: csv.DictWriter no agrega ninguna columna de indice, y con pandas seria to_csv(index=False)

Que hacer con cada defecto

DefectoDondeAccionAdonde va
campo obligatorio ausente4 filas: correo en la 5 y en la 33, telefono en la 12, nombre en la 19rechazar rechazar la fila enteracontactos_rechazados.csv con motivo ausente
el token N/A en correofila 33tratarlo tratarlo como ausente, igual que la celda vacia. La lista de tokens es NULOS = {'', '-', 'N/A', 'NaN', 'null'}contactos_rechazados.csv con motivo ausente y valor N/A
telefono que no empieza con +54fila 27, con el texto 'no tiene'rechazar rechazar la fila enteracontactos_rechazados.csv con motivo restriccion_violada
correo repetidofilas 8 y 13, las dos con elena.escobar@example.comse se queda la primera aparicion y se rechaza la segunda. La comparacion se hace en minusculascontactos_rechazados.csv con motivo duplicado
correo sin arroba0 filas en este archivola la comprobacion va igual: es la misma regla que EJ-5.2 aplica sobre clientes_crudos, donde si hay 11 casoscontactos_rechazados.csv con motivo restriccion_violada
Orden de comprobacion

Una fila puede tener mas de un problema. Se informa solo el primero de esta lista:

  1. ausente en nombre, correo, telefono o ciudad, en ese orden de columnas
  2. correo sin arroba
  3. telefono que no empieza con +54
  4. correo duplicado, comparando en minusculas contra las filas ya aceptadas

Una fila se rechaza UNA vez, con el primer defecto que aparece. Y el duplicado va ultimo a proposito: una fila que ya se rechazo por otra cosa no debe ocupar el lugar de un correo, o el duplicado se detectaria contra una fila que no llego a la salida.

Conteos clave

Si estos numeros no te dan, algo se desvio antes de que llegues a comparar los archivos.

filas de entrada40
contactos_validos.csv34
contactos_rechazados.csv6
por motivoausente: 4, restriccion_violada: 1, duplicado: 1

Invariantes

Comprobaciones que tu resultado tiene que cumplir. Corrilas vos mismo antes de comparar los archivos:

len(validos) + len(rechazados) == 40
len(validos) == 34
validos['correo'].is_unique
(validos['correo'] == validos['correo'].str.lower()).all()
validos['correo'].str.contains('@').all()
validos['telefono'].str.startswith('+54').all()
not validos.isna().any().any()
rechazados['fila'].is_unique
rechazados['fila'].between(1, 40).all()
set(rechazados['motivo']) <= {'ausente', 'restriccion_violada', 'duplicado'}
validos['correo'].is_monotonic_increasing
PISTASSi te trabas, abri esto
  • newline='' va en el open, al leer y al escribir. Sin eso, el CSV de salida se abre en Excel con una fila vacia entre cada dos.
  • Del CSV todo llega como texto: 'fila' es el unico numero de las dos salidas, y sale de enumerate(..., start=1), no de una columna del archivo.
  • El duplicado necesita memoria: un set con los correos ya aceptados. Y se guarda el correo YA normalizado, o la segunda aparicion escrita distinto no se detecta.
  • El assert len(validos) + len(rechazados) == 40 antes de escribir nada. Si no da, hay una fila que no fue ni aceptada ni rechazada.

Así tienen que quedar

contactos_validos.csv (objetivo) · 34 filas, se muestran 5
nombrecorreotelefonociudad
Agustín Gómezagustin.gomez@example.com+54 11 5555-0767Paraná
Agustín Peñaagustin.pena@example.com+54 11 5555-0474La Plata
Carla Gutiérrezcarla.gutierrez@example.com+54 11 5555-0711Paraná
Diego Ibarradiego.ibarra@example.com+54 11 5555-0745Tucumán
Elena Escobarelena.escobar@example.com+54 11 5555-0147Bahía Blanca
contactos_rechazados.csv (objetivo) · 6 filas, se muestran 5
filacolumnamotivovalor
5correoausentevacio
12telefonoausentevacio
13correoduplicadoelena.escobar@example.com
19nombreausentevacio
27telefonorestriccion_violadano tiene
El orden de las comprobaciones es parte del contrato

Una fila se rechaza una sola vez, con el primer defecto que aparece. Y el duplicado va último a propósito: si una fila que ya se rechazó por otra cosa ocupara el lugar de un correo, el duplicado se detectaría contra una fila que nunca llegó a la salida.

Es el tipo de decisión que no cambia si el archivo está limpio y que cambia el resultado en cuanto no lo está. Por eso está escrita.

Tres cosas que se olvidan
  • newline="" en el open, al leer y al escribir. Sin eso, el CSV de salida se abre en Excel con una fila vacía entre cada dos.
  • escritor.writeheader() antes de las filas, aunque no haya ninguna. Un archivo con cabecera y cero filas dice «revisé y no encontré nada»; uno vacío no dice nada.
  • El set de correos vistos guarda el correo ya normalizado. Si guardás el original, una segunda aparición escrita con otras mayúsculas no se detecta.

Antes de escribir nada

assert len(validos) + len(rechazados) == 40

Es el invariante de la lección 1.6 y atrapa la clase entera de errores: si no da, hay una fila que no fue ni aceptada ni rechazada, y desapareció sin que nadie se entere.