Ilustración conceptual de puertas que pasan por un mismo punto de revisión sobre un recorrido continuo.

Bucles: repetir operaciones sin repetir código

El resultado que busco es pequeño y bastante poco negociable: cinco puertas revisadas una vez cada una y dos identificadores en el informe de pendientes. No tres porque hemos repetido una vuelta, ni uno porque el programa se cansó antes de terminar. Vamos a construir ese recorrido con un bucle y a comprobar qué ocurre cuando la selección está vacía, tiene una puerta o contiene las cinco.

Repetir una instrucción es una ocupación de una modestia ofensiva para mis ambiciones editoriales. Precisamente por eso prefiero explicarla una vez y dejar que el ordenador se encargue de las siguientes. Utilizaremos estados ficticios ya calculados; el ejercicio enseña a recorrer datos, acumular un resultado y reconocer la condición de parada. No modifica puertas del modelo ni resuelve todavía cómo obtener sus estados.

Tabla de contenidos

Una vuelta trabaja con un elemento concreto

Un bucle ejecuta un bloque de instrucciones repetidamente. En un recorrido de una colección, cada vuelta trabaja con el siguiente elemento según el orden de esa colección. La variable del recorrido cambia el valor que representa en cada paso; el bloque escrito es el mismo. Este mecanismo permite aplicar una operación a tres identificadores sin duplicar tres veces la instrucción que los muestra.

En Python, for recorre directamente los elementos de la lista. La sangría indica qué instrucciones pertenecen al bloque y los dos puntos anuncian su comienzo. No escribimos un contador para decidir qué posición toca: el propio recorrido proporciona el siguiente valor. Ese detalle simplifica el caso en el que queremos tratar cada entrada sin hacer cálculos con su posición.

				
					puertas = ["P01", "P02", "P03"]
for identificador in puertas:
    print("Revisando", identificador)
print("Recorrido terminado")
				
			

Verás tres mensajes, desde Revisando P01 hasta Revisando P03, y después Recorrido terminado. La última instrucción no tiene sangría y se ejecuta una vez cuando termina el recorrido. Si la introdujeras dentro del bloque, aparecería tres veces. El programa no ha confundido el final con el principio; hemos puesto un anuncio de final en cada vuelta. Una organización muy dada a las ceremonias de clausura.

Para seguirlo sin ejecutar, puedes leer el bloque sustituyendo mentalmente identificador por P01, después P02 y después P03. En cada vuelta el nombre recibe el valor siguiente. La guía de control de flujo de Python explica ese recorrido sobre los elementos de una secuencia. Cuando necesitemos posiciones, construiremos esa pregunta expresamente; no hay obligación de convertir cada colección en una carrera de índices.

El resultado se conserva fuera de cada vuelta

Pasemos al informe prometido. Cada entrada agrupa un identificador y un estado conocido: cumple, incumple o no evaluable. En Python utilizaremos parejas de valores; en cada vuelta los dos nombres del for reciben los componentes de una pareja. Esa agrupación mantiene juntos el identificador y el estado que le corresponde, en lugar de confiar en dos listas que alguien tendrá que mantener alineadas por fe.

Nuestra regla de salida es concreta: añadir al informe de pendientes todas las entradas cuyo estado no sea cumple. Incluye por tanto los incumplimientos y los casos no evaluables. No significa que ambos problemas sean iguales; solo que ninguno debe desaparecer del trabajo pendiente. El estado de cada entrada sigue disponible en los datos originales y una herramienta posterior podría conservar además su motivo.

				
					puertas = [
    ("P01", "cumple"),
    ("P02", "incumple"),
    ("P03", "no evaluable"),
    ("P04", "cumple"),
    ("P05", "cumple"),
]
pendientes = []
revisadas = 0

for identificador, estado in puertas:
    revisadas += 1
    if estado != "cumple":
        pendientes.append(identificador)

print("Revisadas:", revisadas)
print("Pendientes:", ", ".join(pendientes))
				
			

El programa imprime Revisadas: 5 y Pendientes: P02, P03. revisadas += 1 aumenta el contador en cada vuelta. La lista de pendientes se crea antes del recorrido para conservar lo añadido en las vueltas anteriores. Si la reiniciaras dentro del bucle, borrarías el resultado acumulado antes de comprobar la puerta siguiente. El último registro podría dejar un informe vacío después de cuatro decisiones correctas. Mucho movimiento para olvidar sistemáticamente lo que acabamos de hacer.

La condición del if no detiene el recorrido. Decide si esa puerta entra en la lista de pendientes y después deja pasar a la siguiente. Si una entrada ya era un incumplimiento, la añadimos una vez; el programa no necesita volver a clasificarla aquí. Hemos separado el estado calculado de la operación que prepara el informe, lo que permite comprobar el recorrido sin abrir un modelo ni simular parámetros que todavía no estamos leyendo.

En C# el recorrido directo se llama foreach

Para expresar el mismo trabajo en C#, foreach entrega cada entrada de la colección al bloque. El programa siguiente utiliza un array de parejas con nombres para sus componentes: Id y Estado. Ese nombre permite leer puerta.Estado en la condición y puerta.Id al añadir el resultado. Puedes guardarlo como Program.cs en una consola dirigida a .NET 8.

				
					using System;
using System.Collections.Generic;

var puertas = new (string Id, string Estado)[]
{
    ("P01", "cumple"),
    ("P02", "incumple"),
    ("P03", "no evaluable"),
    ("P04", "cumple"),
    ("P05", "cumple")
};
var pendientes = new List<string>();
int revisadas = 0;

foreach (var puerta in puertas)
{
    revisadas += 1;
    if (puerta.Estado != "cumple")
    {
        pendientes.Add(puerta.Id);
    }
}

Console.WriteLine($"Revisadas: {revisadas}");
Console.WriteLine($"Pendientes: {string.Join(", ", pendientes)}");
				
			

La salida coincide con Python: cinco revisadas y P02, P03 como pendientes. La sintaxis cambia, pero podemos contrastar el mismo contrato de entrada y salida. List<string> permite ir añadiendo identificadores y string.Join los presenta separados por comas. La instrucción que prepara ese texto está fuera del bucle porque queremos un informe del recorrido completo, no cinco informes parciales que después alguien tenga que volver a unir.

C# también tiene for, donde suelen aparecer una inicialización, una condición y una actualización del contador. Es útil cuando el índice forma parte del trabajo. No elegiría esa forma solo porque se parezca de nombre al for de Python: ambos lenguajes ofrecen construcciones con recorridos diferentes bajo palabras conocidas. Para recorrer todos los elementos de nuestro array, foreach expresa directamente la intención y evita mantener un índice que no utilizamos para nada más.

Ni este bucle ni el de Python eliminan duplicados de los datos. Si P02 aparece dos veces entre las entradas y ambas se consideran pendientes, aparecerá dos veces en la salida. «Una vez por entrada» y «una vez por puerta única» son promesas distintas. La segunda requiere acordar qué identifica una puerta y qué hacer con registros repetidos; añadir un bucle no concede esa política por generación espontánea.

While necesita una condición que deje de cumplirse

Hay recorridos donde la repetición depende de una condición. while comprueba esa condición antes de cada vuelta y ejecuta el bloque mientras sea verdadera. Para comprender su parada utilizaremos una lista de identificadores y un índice que empieza en cero. El bloque muestra la posición actual y luego la aumenta en uno; cuando el índice alcanza la longitud, ya no hay otra posición válida y la condición se vuelve falsa.

				
					puertas = ["P01", "P02", "P03"]
indice = 0
while indice < len(puertas):
    print("Revisando", puertas[indice])
    indice += 1
print("Vueltas:", indice)
				
			

La salida muestra las tres puertas y Vueltas: 3. El valor tres sirve aquí para terminar; no se utiliza para consultar una cuarta posición. El operador es menor que, no menor o igual que. Esta diferencia es el mismo límite que estudiamos con las listas: una colección de tres elementos permite consultar las posiciones cero, uno y dos. El contador necesita poder llegar a tres precisamente para demostrar que el recorrido ha acabado.

En C# podemos escribir la misma condición y el mismo avance. Este programa es independiente del anterior y permite seguir las posiciones sin depender de ningún dato externo. La referencia de instrucciones de iteración de C# describe la comprobación previa de while; si la condición inicial es falsa, no se ejecuta ninguna vuelta.

				
					using System;

string[] puertas = { "P01", "P02", "P03" };
int indice = 0;
while (indice < puertas.Length)
{
    Console.WriteLine($"Revisando {puertas[indice]}");
    indice += 1;
}
Console.WriteLine($"Vueltas: {indice}");
				
			

En este ejemplo elegiría el recorrido directo del primer apartado: expresa mejor que queremos todas las entradas. while sirve aquí para hacer visible quién cambia la condición. Si eliminas el incremento, la primera posición se repetirá indefinidamente mientras la colección siga teniendo elementos. No hace falta ejecutar esa versión para comprobar el problema; basta con observar que ninguna instrucción cambia el índice ni la longitud. Mi paciencia ficticia puede ser infinita; el proceso que acabamos de escribir no necesita imitarla.

En una tarea real, una condición que espera una respuesta externa necesita además límites y un resultado de fallo claro. Esa decisión merece otra explicación; un while no sabe cuánto tiempo de espera es aceptable. Por ahora nuestra condición depende únicamente de una lista estable y un contador que controlamos. Podemos demostrar su terminación sin recurrir a «ya responderá el servidor», una unidad de tiempo bastante poco recomendable.

Comprueba las entradas que hacen incómodo el resultado

Con cinco registros, el informe correcto tiene cinco revisadas y dos pendientes. Si sustituyes la colección por una vacía, el recorrido directo no ejecuta el bloque y conserva cero revisadas y cero pendientes. No se accede a una primera puerta inexistente. Con una sola entrada, el bloque se ejecuta una vez y su estado decide si el identificador debe aparecer en el resultado. Esos tres tamaños permiten detectar supuestos que el ejemplo grande puede ocultar.

La comprobación no termina en contar las vueltas. Un contador con cinco podría convivir con un informe que ha duplicado un identificador y perdido otro. Para estos datos conocemos la salida exacta: P02 y P03, en ese orden. Compararla con lo obtenido permite distinguir un recorrido completo de un resultado correcto. Yo exigiría ambas cosas antes de dar por resuelto el ejercicio; una cifra redonda tiene una capacidad extraordinaria para tranquilizar reuniones sin explicar nada.

También conservaría la colección de entrada mientras construimos la salida. Quitar elementos de la misma lista que estamos recorriendo puede alterar lo que se visita, y el comportamiento depende de la estructura y del lenguaje. En este diseño no necesitamos resolver ese conflicto: leemos las entradas y añadimos pendientes a otra colección. Si el objetivo cambia a modificar datos del modelo, habrá que estudiar además las reglas de su API y sus transacciones, no trasladar este ejemplo de consola sin más.

Puedes comprobarlo cambiando P04 a incumple: el informe debe incorporar P04 y seguir mostrando cinco revisadas. Después devuelve P04 a su estado original y prueba la selección vacía. ¿Qué comprobación suele faltar en los scripts que revisas: el caso sin entradas, el contenido exacto del resultado o la condición de parada? Esa respuesta sí merece un comentario. Afirmar que «el bucle funciona» después de verlo girar cinco veces todavía deja demasiado trabajo al siguiente humano que tenga que fiarse de él.

Artículos relacionados

Respuestas

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