Loops Anidados
Un bucle dentro de otro multiplica las vueltas. Aprende a leerlo, a reconocer cuándo sobra y a sustituirlo por una búsqueda en un Set o un Map.
✓ En esta sub-lección
- 01Predecir cuántas vueltas hace un bucle anidado y qué hacen break y continue dentro de él.
- 02Reconocer el anidado que solo sirve para buscar coincidencias.
- 03Sustituirlo por dos bucles seguidos y un Set o Map intermedio.
La nutria: ¿Te acuerdas? · Repaso de la lección 6
Recorres casos y quieres saltarte los cerrados y seguir con el siguiente. ¿Qué usas?
Tarde o temprano tendrás dos listas y una pregunta que las cruza: ¿qué leads son de empresas que ya son clientes?, ¿qué contactos pertenecen a estas cuentas? La primera solución que se le ocurre a todo el mundo es un bucle dentro de otro. Funciona. Y con volumen real, es la que tumba la transacción.
La nutria: El paralelo de Admin
Cómo se lee un bucle anidado
El bucle de fuera avanza una vez; el de dentro da todas sus vueltas; el de fuera avanza otra vez; el de dentro vuelve a empezar desde cero. Por eso las vueltas se multiplican: 3 de fuera × 4 de dentro son 12 ejecuciones del cuerpo interior.
for (Integer week = 1; week <= 3; week++) {
for (Integer day = 1; day <= 4; day++) {
System.debug('Semana ' + week + ', día ' + day);
}
}
// 12 líneas: semana 1 días 1-4, semana 2 días 1-4, semana 3 días 1-4El problema: las vueltas se disparan
Cruzar 200 leads con 200 cuentas mediante dos bucles anidados son 40.000 comparaciones. Con 2.000 cuentas, 400.000. Cada una consume , y un recibe hasta un de 200 registros de golpe. El código que en tu prueba con 3 registros iba perfecto es el que un día de carga masiva lanza «Apex CPU time limit exceeded».
ANIDADO
for (Lead l : leads)
for (Account a : accounts)
if (l.Company == a.Name) …CON UN SET
for (Account a : accounts)
names.add(a.Name);
for (Lead l : leads)
if (names.contains(l.Company)) …ANIDADO40.000 vueltas
CON UN SET400 vueltas
100 veces más trabajo anidado. El anidado crece con el cuadrado: si duplicas los registros, cuadruplicas las vueltas. El Set crece en línea recta, porque contains() responde sin recorrer nada. Y el tiempo de CPU de una transacción tiene límite.
La solución: dos bucles seguidos y un BUSCARV
En lugar de meter un bucle dentro de otro, pones uno detrás de otro. El primero recorre una lista y construye un Set (si solo necesitas saber «¿está?») o un Map (si además necesitas el registro). El segundo recorre la otra lista y, en cada vuelta, pregunta al Set o al Map con contains() o get(): una consulta directa, sin recorrer nada. 200 + 200 = 400 vueltas en vez de 40.000.
// ❌ Anidado: cuentas × leads comparaciones
for (Lead l : leads) {
for (Account a : customers) {
if (l.Company == a.Name) {
l.Rating = 'Hot';
}
}
}
// ✅ Dos bucles seguidos: cuentas + leads vueltas
Set<String> customerNames = new Set<String>();
for (Account a : customers) {
customerNames.add(a.Name);
}
for (Lead l : leads) {
if (customerNames.contains(l.Company)) {
l.Rating = 'Hot';
}
}