Ilustración conceptual de cuatro puertas con banderas de error en la segunda y cuarta posiciones, conservadas en el informe.

enumerate() en Python: recorrer datos conservando su posición

«Hay un código vacío en la tabla». Una observación fascinante, salvo para quien tiene que encontrarlo. Un informe útil necesita llevar al dato que debe revisarse: qué entrada, de qué origen y con qué identificador. Si el diagnóstico obliga a repetir a mano toda la búsqueda que acababa de hacer el programa, hemos automatizado la redacción del problema y dejado el trabajo donde estaba. Admito que tiene cierta elegancia administrativa.

enumerate() añade un contador al recorrido de una colección en Python. Vamos a utilizarlo para conservar la posición de las entradas que contienen errores, entender qué cambia al filtrar y construir el mismo informe con C#. La posición nos ayudará a localizar un dato dentro de esta entrega; no la confundiremos con la identidad de una puerta, que necesita otra clase de compromiso.

Tabla de contenidos

Un número de fila orienta, pero no identifica al elemento

Trabajaremos con cuatro registros didácticos de puertas. Cada uno contiene un identificador y un código; P02 y P04 tienen el código vacío. Queremos que el informe indique las posiciones 2 y 4, además de esos identificadores. Así quien revise la misma colección podrá localizar el registro y confirmar que está mirando la puerta correcta. No es una lectura de Revit ni una importación real de Excel: los datos estarán escritos en el programa para hacer visible el recorrido.

Esa referencia solo tiene sentido si conservamos el contexto. La posición 4 de una tabla no explica nada sin saber a qué tabla y versión pertenece. Si alguien ordena la entrada, la posición de una puerta puede cambiar aunque el identificador permanezca. Al compartir un informe real, guarda también el archivo o lote de origen y evita presentar un número de fila como una dirección universal. El programa no ha inventado un GPS para puertas; está contando vueltas.

Hay además dos numeraciones que conviene separar. El índice de una lista de Python empieza en cero; para hablar con quien revisa una tabla suele resultar más cómodo contar desde uno. Puedes elegir esa base al usar enumerate, pero cambiar el contador no modifica los índices de la colección ni añade un encabezado. Es una etiqueta que acompaña al recorrido, no una reconfiguración de cómo funciona la lista.

Si necesitas actualizar un elemento a partir del informe, utiliza una clave y comprueba el destino, como en el cruce de datos por identificador. La posición es útil para investigar una entrega concreta; la clave permite buscar la correspondencia adecuada. Mantener ambas en el diagnóstico cuesta poco y evita que una ordenación de la hoja cambie a quién le estamos atribuyendo el error.

Python: numerar antes de decidir qué entradas fallan

Guarda este programa completo como informe_filas.py. Utiliza Python 3 y no requiere paquetes adicionales. La función devuelve los errores; el código final los imprime. El contador se asigna al recorrer todas las entradas y solo después se comprueba el código. De ese modo, una puerta correcta también ocupa su posición en el origen, aunque no aparezca en el informe de errores.

				
					def revisar(filas, inicio=1):
    errores = []
    for numero, (identificador, codigo) in enumerate(filas, start=inicio):
        if codigo == "":
            errores.append((numero, identificador, "codigo vacio"))
    return errores


filas = [("P01", "D01"), ("P02", ""),
         ("P03", "D03"), ("P04", "")]
for numero, identificador, motivo in revisar(filas):
    print(f"{numero} | {identificador} | {motivo}")
				
			

Desde la carpeta del archivo, ejecútalo:

				
					python informe_filas.py
				
			

La salida será 2 | P02 | codigo vacio y 4 | P04 | codigo vacio. El bucle recibe en cada vuelta una pareja: contador y registro. A su vez, el registro contiene identificador y código. Por eso la cabecera tiene numero, (identificador, codigo): estamos dando nombre a esas piezas para utilizarlas sin acceder repetidamente a posiciones numéricas difíciles de leer.

start=inicio fija el primer valor del contador. Con inicio=1, el primer registro recibe 1; con inicio=0, recibe 0. Para esta entrada, llamar a revisar(filas, inicio=0) produciría errores en 1 y 3. No han cambiado las puertas que fallan: ha cambiado la convención con la que describimos dónde estaban. Documenta esa convención en lugar de obligar al lector a deducir si el informe cuenta como Python, como una hoja o como a alguien le pareció oportuno ese martes.

La regla es deliberadamente pequeña: solo "" se considera código vacío. Un espacio, None o un código no incluido en el catálogo requieren otras reglas; no están validados por este ejemplo. Queremos aprender a conservar la referencia del error, no esconder cinco decisiones de calidad dentro de una función que se supone que solo enseña a contar. Una vez entiendas el recorrido, podrás ampliar el motivo y mantener la misma forma del diagnóstico.

Filtrar primero cambia lo que estás numerando

Supón que antes de llamar a revisar construyes una colección que contiene únicamente P02 y P04. Al numerar esa nueva colección desde uno, obtendrás 1 y 2. El resultado es correcto como numeración del subconjunto, pero esas cifras ya no señalan las posiciones 2 y 4 de la entrada original. enumerate no conserva el historial de las operaciones que hiciste antes de entregarle los datos. Su memoria autobiográfica, por una vez, es exactamente la prometida: ninguna.

Esto importa cuando un informe mezcla dos necesidades. Puedes querer un número correlativo para las incidencias —incidencia 1 e incidencia 2— y también la posición de cada registro en el origen. Son campos distintos. Conserva primero la referencia del origen, filtra después y, si necesitas numerar los errores para presentarlos, añade un segundo contador con otro nombre. Llamar «fila» a todos los números no simplifica el informe; traslada la ambigüedad a quien tenga que corregirlo.

Nuestro programa enumera la colección completa y añade al resultado solo las entradas que fallan. Por eso los huecos entre 2 y 4 son una información útil: hubo registros intermedios que no generaron error. Un informe de errores no necesita fingir que sus referencias de origen son consecutivas. Reordenarlo para agrupar motivos también es válido si cada entrada mantiene el número de origen que ya había recibido.

La misma precaución se aplica a los encabezados. Si has leído un archivo con una fila de cabecera y quieres que el primer dato se etiquete como 2, puedes elegir inicio=2 siempre que el formato y el recorrido justifiquen esa correspondencia. No lo generalices a cualquier CSV: un registro con texto entre comillas puede ocupar varias líneas físicas. Un contador de registros leídos y un número de línea del archivo no son automáticamente la misma medida. Para este ejercicio hablamos de posiciones de los cuatro registros en memoria.

C#: añadir el índice con Select y filtrar después

En una aplicación de consola de .NET 8 podemos conseguir el mismo resultado con la sobrecarga de Select que recibe el elemento y su índice. Ese índice comienza en cero; sumaremos inicio para definir la numeración del informe. Crea el proyecto:

				
					dotnet new console --framework net8.0 -n InformeFilas
				
			

Sustituye InformeFilas/Program.cs por este programa completo. El primer Select añade Numero a todas las filas. Where selecciona después las que tienen código vacío y el último Select prepara los tres campos que devuelve la función. La colocación del filtro es la que conserva la referencia del origen; escribir LINQ en varias líneas no la garantiza por sí solo.

				
					using System;
using System.Linq;

static (int Numero, string Id, string Motivo)[] Revisar(
    (string Id, string Codigo)[] filas, int inicio = 1)
{
    return filas.Select((fila, indice) =>
            (Numero: indice + inicio, fila.Id, fila.Codigo))
        .Where(fila => fila.Codigo == "")
        .Select(fila => (fila.Numero, fila.Id, Motivo: "codigo vacio"))
        .ToArray();
}

(string Id, string Codigo)[] filas =
    [("P01", "D01"), ("P02", ""), ("P03", "D03"), ("P04", "")];
foreach (var (numero, identificador, motivo) in Revisar(filas))
    Console.WriteLine($"{numero} | {identificador} | {motivo}");
				
			

Ejecuta el proyecto:

				
					dotnet run --project InformeFilas
				
			

Verás las mismas dos líneas que en Python, con las posiciones 2 y 4. Si mueves Where antes del primer Select, el índice se calculará sobre la secuencia ya filtrada y perderás esa numeración de origen. Las operaciones siguen siendo válidas para el lenguaje; ha cambiado la pregunta que responde el resultado. Este es un error especialmente cómodo de mantener porque compila sin quejarse.

En este ejemplo, ToArray materializa el resultado antes de devolverlo. Así quien recibe el informe tiene las entradas preparadas, en lugar de una consulta pendiente de recorrido. No convierte el array original en inmutable ni prueba que los datos cumplan un catálogo: solo hace explícito cuándo obtenemos este resultado. La referencia oficial de Select explica la sobrecarga con índice y su ejecución diferida.

Probar la referencia vale más que decorar el mensaje de error

Empieza por cambiar inicio a 0 y a 2 en ambos ejemplos. Para las dos puertas con código vacío debes obtener, respectivamente, 1 y 3, o 3 y 5. Después prueba una colección vacía y otra con todos los códigos rellenos: en ambas el informe será vacío, aunque por motivos distintos. Si tu herramienta necesita distinguir «no recibí registros» de «no encontré errores», añade ese dato al resumen del proceso; no puede deducirse solo de la lista de incidencias.

Pon dos entradas con el mismo identificador y código vacío. El informe debe conservar ambas posiciones. enumerate no elimina duplicados ni comprueba la unicidad de las claves. Esta es una ventaja para investigar: puedes señalar las dos apariciones sin que una sobrescriba a la otra. Resolver si ese identificador puede repetirse exige una regla de identidad independiente, como ya vimos al cruzar tablas.

Por último, invierte el orden de los cuatro registros y vuelve a generar el informe. P04 aparecerá ahora en 1 y P02 en 3. Es la demostración más clara de qué estás guardando: una referencia a esta secuencia, no una propiedad estable de la puerta. Si el diagnóstico conserva también el identificador y el lote de entrada, puedes explicar el cambio de posición sin perder el elemento del que estabas hablando.

La documentación de enumerate de Python desarrolla el contador y su valor inicial. Para aplicarlo bien, la decisión útil viene antes: ¿quieres numerar los resultados o localizar los registros de origen? Yo conservaría ambos campos cuando cumplan funciones distintas. Y si recibes un informe que solo anuncia «dato incorrecto», pregunta qué necesitaría otra persona para encontrarlo sin volver a ejecutar mentalmente todo el programa. Esa respuesta debería formar parte del informe, no de una llamada posterior.

Artículos relacionados

Respuestas

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *