Ir al contenido

Capítulo 7: Bucles (Loops)

Parte I - Sección 2: Programación desde cero - Nivel: Principiante


Al finalizar este capítulo serás capaz de:

  • Usar bucles for para repetir código un número específico de veces
  • Usar foreach para iterar colecciones de datos
  • Usar while para repetir mientras se cumpla una condición
  • Usar do-while cuando necesitas ejecutar al menos una vez
  • Controlar bucles con break y continue
  • Anidar bucles para procesar estructuras complejas
  • Construir procesadores automáticos de listas de componentes

Antes de comenzar este capítulo debes:

  • ✅ Haber completado el Capítulo 6
  • ✅ Entender estructuras if/else y switch
  • ✅ Conocer variables y operadores
  • ✅ Saber usar operadores de comparación

Procesador Automático de Componentes Eléctricos

Al final de este capítulo habrás construido un script que:

  • Procesa listas de componentes automáticamente
  • Calcula resistencias en serie y paralelo
  • Genera reportes de múltiples circuitos
  • Valida datos de forma masiva

Tiempo estimado: 50-60 minutos


1. Introducción: El problema de las tareas repetitivas

Sección titulada «1. Introducción: El problema de las tareas repetitivas»

Imagina que necesitas:

  • Verificar 50 componentes en una lista
  • Calcular la resistencia total de 20 resistencias en serie
  • Generar 15 reportes con el mismo formato
  • Procesar 100 cables para verificar secciones

Sin bucles:

double resistencia1 = 100.0;
double resistencia2 = 220.0;
double resistencia3 = 330.0;
double resistencia4 = 470.0;
double resistencia5 = 560.0;
// ... repetir 15 veces más
double total = resistencia1 + resistencia2 + resistencia3 + resistencia4 + resistencia5;
// Tedioso, propenso a errores, difícil de mantener

Con bucles:

double[] resistencias = {100, 220, 330, 470, 560, 680, 820, 1000};
double total = 0;
for (int i = 0; i < resistencias.Length; i++)
{
total += resistencias[i];
}
// Limpio, escalable, fácil de mantener

Los bucles son la base de la automatización.


El bucle for se usa cuando sabes cuántas veces quieres repetir algo.

for (inicialización; condición; incremento)
{
// Código que se repite
}

Ejemplo simple:

for (int i = 0; i < 5; i++)
{
MessageBox.Show("Iteración número: " + i);
}
// Muestra: 0, 1, 2, 3, 4

Anatomía:

for (int i = 0; i < 5; i++)
↑ ↑ ↑
| | └─ Incremento: ejecuta después de cada iteración
| └─────────── Condición: evalúa antes de cada iteración
└──────────────────────── Inicialización: ejecuta una sola vez al inicio
  1. Inicialización: int i = 0 - Crea variable contador
  2. Condición: i < 5 - ¿Continuar? Si es true, ejecuta el bloque
  3. Ejecución: Ejecuta el código dentro de { }
  4. Incremento: i++ - Aumenta el contador
  5. Vuelve al paso 2

Flujo visual:

i=0 → ¿i<5? Sí → Ejecuta → i++ → i=1
i=1 → ¿i<5? Sí → Ejecuta → i++ → i=2
i=2 → ¿i<5? Sí → Ejecuta → i++ → i=3
i=3 → ¿i<5? Sí → Ejecuta → i++ → i=4
i=4 → ¿i<5? Sí → Ejecuta → i++ → i=5
i=5 → ¿i<5? No → Termina

Ejemplo 1: Generar secuencia de páginas

string paginas = "Páginas del proyecto:\n";
for (int numeroPagina = 1; numeroPagina <= 10; numeroPagina++)
{
paginas += "Página " + numeroPagina + "\n";
}
MessageBox.Show(paginas);

Ejemplo 2: Calcular potencias de 2

string resultado = "Potencias de 2:\n";
for (int exponente = 0; exponente <= 10; exponente++)
{
double potencia = Math.Pow(2, exponente);
resultado += string.Format("2^{0} = {1}\n", exponente, potencia);
}
MessageBox.Show(resultado);
// 2^0 = 1
// 2^1 = 2
// 2^2 = 4
// ...

Ejemplo 3: Sumar resistencias en serie

double[] resistencias = {100, 220, 330, 470, 560};
double resistenciaTotal = 0;
for (int i = 0; i < resistencias.Length; i++)
{
resistenciaTotal += resistencias[i];
}
MessageBox.Show(string.Format("Resistencia total en serie: {0:F2} Ω", resistenciaTotal));
// Resistencia total en serie: 1680.00 Ω

Contar hacia atrás:

for (int i = 10; i >= 1; i--)
{
MessageBox.Show("Cuenta atrás: " + i);
}
// 10, 9, 8, 7, 6, 5, 4, 3, 2, 1

Incremento de 2 en 2:

for (int i = 0; i <= 10; i += 2)
{
MessageBox.Show("Número par: " + i);
}
// 0, 2, 4, 6, 8, 10

Múltiples variables (poco común):

for (int i = 0, j = 10; i < j; i++, j--)
{
MessageBox.Show(string.Format("i={0}, j={1}", i, j));
}
// i=0, j=10
// i=1, j=9
// i=2, j=8
// ...

El bucle foreach se usa para recorrer colecciones (arrays, listas) sin necesidad de índices.

foreach (tipo variable in coleccion)
{
// Código que se ejecuta para cada elemento
}

Ejemplo simple:

string[] fabricantes = {"Siemens", "Schneider", "ABB", "Eaton"};
foreach (string fabricante in fabricantes)
{
MessageBox.Show("Fabricante: " + fabricante);
}

Con for:

string[] componentes = {"Contactor", "Relé", "Guardamotor"};
for (int i = 0; i < componentes.Length; i++)
{
MessageBox.Show(componentes[i]);
}

Con foreach (más simple):

string[] componentes = {"Contactor", "Relé", "Guardamotor"};
foreach (string componente in componentes)
{
MessageBox.Show(componente);
}

Cuándo usar cada uno:

  • foreach: Cuando solo necesitas recorrer todos los elementos
  • for: Cuando necesitas el índice, o quieres saltar elementos, o modificar el array

Ejemplo 1: Validar voltajes

double[] voltajesMedidos = {228.5, 232.1, 229.8, 235.2, 226.4};
int voltajesOK = 0;
int voltajesFuera = 0;
foreach (double voltaje in voltajesMedidos)
{
if (voltaje >= 207 && voltaje <= 253)
{
voltajesOK++;
}
else
{
voltajesFuera++;
}
}
string mensaje = string.Format(
"Voltajes dentro de rango: {0}\nVoltajes fuera de rango: {1}",
voltajesOK,
voltajesFuera
);
MessageBox.Show(mensaje);

Ejemplo 2: Calcular corriente total

double[] corrientesCircuitos = {15.5, 8.2, 12.7, 20.3, 6.8};
double corrienteTotal = 0;
foreach (double corriente in corrientesCircuitos)
{
corrienteTotal += corriente;
}
MessageBox.Show(string.Format("Corriente total: {0:F2} A", corrienteTotal));
// Corriente total: 63.50 A

Ejemplo 3: Buscar componente específico

string[] componentes = {"K1", "Q1", "F1", "K2", "Q2"};
string buscado = "F1";
bool encontrado = false;
foreach (string componente in componentes)
{
if (componente == buscado)
{
encontrado = true;
break; // Sal del bucle cuando lo encuentres
}
}
if (encontrado)
{
MessageBox.Show(buscado + " encontrado en la lista");
}
else
{
MessageBox.Show(buscado + " NO encontrado");
}

4. Bucle while - Mientras se cumpla una condición

Sección titulada «4. Bucle while - Mientras se cumpla una condición»

El bucle while se usa cuando no sabes cuántas iteraciones necesitarás, pero tienes una condición de parada.

while (condicion)
{
// Código que se repite mientras condicion sea true
}

Ejemplo simple:

int contador = 0;
while (contador < 5)
{
MessageBox.Show("Contador: " + contador);
contador++;
}
// 0, 1, 2, 3, 4

Con for (sabes las iteraciones):

for (int i = 0; i < 5; i++)
{
MessageBox.Show("i: " + i);
}

Con while (condición dinámica):

double voltaje = 230.0;
int iteraciones = 0;
while (voltaje >= 207.0 && voltaje <= 253.0)
{
MessageBox.Show(string.Format("Voltaje OK: {0:F1}V", voltaje));
voltaje -= 5.0; // Simular caída de voltaje
iteraciones++;
if (iteraciones > 10) break; // Seguridad para evitar bucle infinito
}

Ejemplo 1: Dividir corriente hasta alcanzar límite

double corrienteTotal = 100.0; // A
double corrientePorCircuito = 16.0; // A
int numeroCir cuitos = 0;
while (corrienteTotal > 0)
{
corrienteTotal -= corrientePorCircuito;
numeroCir cuitos++;
}
MessageBox.Show(string.Format("Se necesitan {0} circuitos de 16A", numeroCir cuitos));
// Se necesitan 7 circuitos de 16A

Ejemplo 2: Encontrar sección de cable adecuada

double corrienteCircuito = 28.5; // A
double[] seccionesDisponibles = {1.5, 2.5, 4.0, 6.0, 10.0, 16.0};
double[] corrientesAdmisibles = {15.0, 21.0, 27.0, 36.0, 50.0, 68.0};
int indice = 0;
while (indice < seccionesDisponibles.Length)
{
if (corrientesAdmisibles[indice] >= corrienteCircuito)
{
MessageBox.Show(string.Format(
"Para {0}A, usar cable de {1}mm² (admite {2}A)",
corrienteCircuito,
seccionesDisponibles[indice],
corrientesAdmisibles[indice]
));
break;
}
indice++;
}

Ejemplo 3: Validación de entrada

bool entradaValida = false;
int intentos = 0;
double voltaje = 150.0; // Simulación de entrada de usuario
while (!entradaValida && intentos < 3)
{
if (voltaje >= 207.0 && voltaje <= 253.0)
{
entradaValida = true;
MessageBox.Show("Voltaje aceptado: " + voltaje + "V");
}
else
{
MessageBox.Show("Voltaje fuera de rango. Intento " + (intentos + 1));
voltaje += 50.0; // Simulación de corrección
intentos++;
}
}
if (!entradaValida)
{
MessageBox.Show("Máximo de intentos alcanzado");
}

Bucle infinito (NUNCA termina):

int contador = 0;
while (contador < 5)
{
MessageBox.Show("Contador: " + contador);
// ¡Olvidaste incrementar contador!
// Este bucle NUNCA termina
}

Solución: Siempre asegúrate de que la condición pueda ser false:

int contador = 0;
while (contador < 5)
{
MessageBox.Show("Contador: " + contador);
contador++; // ← Esto hace que eventualmente contador >= 5
}

5. Bucle do-while - Ejecutar al menos una vez

Sección titulada «5. Bucle do-while - Ejecutar al menos una vez»

El bucle do-while siempre ejecuta al menos una iteración, luego verifica la condición.

do
{
// Código que se ejecuta AL MENOS una vez
} while (condicion);

Diferencia clave con while:

while: Verifica primero, luego ejecuta

int contador = 10;
while (contador < 5)
{
MessageBox.Show("Nunca se ejecuta");
}
// No muestra nada porque 10 < 5 es false desde el inicio

do-while: Ejecuta primero, luego verifica

int contador = 10;
do
{
MessageBox.Show("Se ejecuta una vez: " + contador);
} while (contador < 5);
// Muestra "Se ejecuta una vez: 10" aunque la condición sea false

Ejemplo 1: Menú de opciones (se debe mostrar al menos una vez)

int opcion;
do
{
string menu = "MENÚ:\n1. Validar proyecto\n2. Exportar PDF\n3. Salir\n\nElija opción:";
opcion = 2; // Simulación (en realidad vendría de usuario)
switch (opcion)
{
case 1:
MessageBox.Show("Validando proyecto...");
break;
case 2:
MessageBox.Show("Exportando PDF...");
break;
case 3:
MessageBox.Show("Saliendo...");
break;
default:
MessageBox.Show("Opción no válida");
break;
}
opcion = 3; // Simulación de salir
} while (opcion != 3);

Ejemplo 2: Validar y reintentar

double voltaje;
bool esValido;
do
{
voltaje = 195.0; // Simulación de entrada
esValido = (voltaje >= 207.0 && voltaje <= 253.0);
if (!esValido)
{
MessageBox.Show(string.Format("Voltaje {0}V fuera de rango. Reintentando...", voltaje));
voltaje = 230.0; // Simulación de corrección
esValido = true; // Para salir del ejemplo
}
} while (!esValido);
MessageBox.Show(string.Format("Voltaje válido: {0}V", voltaje));

6. break y continue - Control de flujo en bucles

Sección titulada «6. break y continue - Control de flujo en bucles»
for (int i = 0; i < 10; i++)
{
if (i == 5)
{
break; // Sale del bucle cuando i=5
}
MessageBox.Show("i: " + i);
}
// Muestra: 0, 1, 2, 3, 4 (se detiene en 5)

Ejemplo práctico: Buscar primer componente defectuoso

string[] componentes = {"K1-OK", "Q1-OK", "F1-FALLO", "K2-OK", "Q2-OK"};
string primerDefectuoso = "";
foreach (string componente in componentes)
{
if (componente.Contains("FALLO"))
{
primerDefectuoso = componente;
break; // No necesitamos seguir buscando
}
}
MessageBox.Show("Primer defectuoso: " + primerDefectuoso);
// Primer defectuoso: F1-FALLO

6.2 continue - Saltar a la siguiente iteración

Sección titulada «6.2 continue - Saltar a la siguiente iteración»
for (int i = 0; i < 10; i++)
{
if (i % 2 == 0)
{
continue; // Salta los números pares
}
MessageBox.Show("Impar: " + i);
}
// Muestra: 1, 3, 5, 7, 9

Ejemplo práctico: Procesar solo componentes válidos

string[] componentes = {"K1", "", "Q1", "INVALIDO", "F1", "", "K2"};
string componentesValidos = "Componentes válidos:\n";
foreach (string componente in componentes)
{
// Saltar vacíos o inválidos
if (componente == "" || componente == "INVALIDO")
{
continue;
}
componentesValidos += componente + "\n";
}
MessageBox.Show(componentesValidos);
// K1, Q1, F1, K2
// break: SALE del bucle completamente
for (int i = 0; i < 5; i++)
{
if (i == 2) break;
MessageBox.Show("i: " + i);
}
// Muestra: 0, 1 (termina)
// continue: SALTA a la siguiente iteración
for (int i = 0; i < 5; i++)
{
if (i == 2) continue;
MessageBox.Show("i: " + i);
}
// Muestra: 0, 1, 3, 4 (salta el 2, pero continúa)

7. Bucles anidados - Bucles dentro de bucles

Sección titulada «7. Bucles anidados - Bucles dentro de bucles»

Puedes colocar un bucle dentro de otro para procesar estructuras bidimensionales o combinaciones.

for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 3; j++)
{
MessageBox.Show(string.Format("i={0}, j={1}", i, j));
}
}
// i=0, j=0
// i=0, j=1
// i=0, j=2
// i=1, j=0
// i=1, j=1
// ...

Iteraciones totales: 3 × 3 = 9

Ejemplo 1: Procesar múltiples proyectos con múltiples idiomas

string[] proyectos = {"Proyecto_A", "Proyecto_B", "Proyecto_C"};
string[] idiomas = {"ES", "EN", "FR"};
string reporte = "Exportaciones a realizar:\n";
foreach (string proyecto in proyectos)
{
foreach (string idioma in idiomas)
{
reporte += string.Format("- {0} en {1}\n", proyecto, idioma);
}
}
MessageBox.Show(reporte);
// Proyecto_A en ES
// Proyecto_A en EN
// Proyecto_A en FR
// Proyecto_B en ES
// ...

Ejemplo 2: Calcular resistencias en matriz (serie + paralelo)

// 3 ramas en paralelo, cada una con 4 resistencias en serie
double[][] resistencias = new double[][]
{
new double[] {100, 220, 330, 470}, // Rama 1
new double[] {150, 270, 390, 510}, // Rama 2
new double[] {180, 300, 420, 560} // Rama 3
};
string reporte = "CÁLCULO DE RESISTENCIAS:\n\n";
// Calcular resistencia de cada rama (serie)
double[] resistenciasPorRama = new double[resistencias.Length];
for (int rama = 0; rama < resistencias.Length; rama++)
{
double resistenciaRama = 0;
for (int r = 0; r < resistencias[rama].Length; r++)
{
resistenciaRama += resistencias[rama][r];
}
resistenciasPorRama[rama] = resistenciaRama;
reporte += string.Format("Rama {0}: {1:F2} Ω\n", rama + 1, resistenciaRama);
}
// Calcular resistencia total en paralelo
// 1/Rtotal = 1/R1 + 1/R2 + 1/R3
double sumaInversos = 0;
for (int i = 0; i < resistenciasPorRama.Length; i++)
{
sumaInversos += 1.0 / resistenciasPorRama[i];
}
double resistenciaTotal = 1.0 / sumaInversos;
reporte += string.Format("\nResistencia total (paralelo): {0:F2} Ω", resistenciaTotal);
MessageBox.Show(reporte);

Ejemplo 3: Generar tabla de multiplicar

string tabla = "TABLA DE VALORES DE CABLES:\n\n";
tabla += "Sección(mm²) | 10A | 16A | 20A | 25A\n";
tabla += "--------------------------------------\n";
double[] secciones = {1.5, 2.5, 4.0, 6.0};
double[] corrientes = {10, 16, 20, 25};
foreach (double seccion in secciones)
{
tabla += string.Format("{0,12} |", seccion);
foreach (double corriente in corrientes)
{
// Caída de tensión simplificada: ΔV = 2 × L × I × ρ / S
double longitud = 50.0; // m
double resistividad = 0.018;
double caidaTension = (2 * longitud * corriente * resistividad) / seccion;
tabla += string.Format(" {0:F1}V |", caidaTension);
}
tabla += "\n";
}
MessageBox.Show(tabla);

3 bucles anidados: 10 × 10 × 10 = 1,000 iteraciones

for (int i = 0; i < 10; i++)
{
for (int j = 0; j < 10; j++)
{
for (int k = 0; k < 10; k++)
{
// 1000 iteraciones
}
}
}

Regla general: Evita más de 2-3 niveles de anidación para mantener el código legible.


💻 Manos a la obra: Construyendo el proyecto

Sección titulada «💻 Manos a la obra: Construyendo el proyecto»

Vamos a crear un Procesador Automático de Componentes Eléctricos que use todos los tipos de bucles.

Paso 1: Estructura básica y datos de entrada

Sección titulada «Paso 1: Estructura básica y datos de entrada»
using System;
using Eplan.EplApi.Base;
using Eplan.EplApi.ApplicationFramework;
public class ProcesadorComponentes
{
[Start]
public void Ejecutar()
{
// ========================================
// DATOS DE ENTRADA
// ========================================
// Lista de componentes a procesar
string[] componentesID = {"K1", "K2", "Q1", "Q2", "F1", "F2", "M1", "M2"};
// Corrientes por componente (en orden)
double[] corrientes = {25.0, 40.0, 16.0, 20.0, 10.0, 16.0, 7.5, 11.0};
// Resistencias para cálculo (Ohmios)
double[] resistenciasSerie = {100, 220, 330, 470, 560};
// Voltajes medidos en diferentes puntos
double[] voltajesMedidos = {232.5, 228.3, 235.1, 226.8, 230.2, 233.7};
}
}

// ========================================
// PROCESAMIENTO 1: VALIDAR COMPONENTES
// ========================================
string reporteComponentes = "=== VALIDACIÓN DE COMPONENTES ===\n\n";
int componentesOK = 0;
int componentesAdvertencia = 0;
for (int i = 0; i < componentesID.Length; i++)
{
string id = componentesID[i];
double corriente = corrientes[i];
// Clasificar según corriente
string clasificacion;
if (corriente < 16.0)
{
clasificacion = "Baja corriente";
componentesOK++;
}
else if (corriente <= 32.0)
{
clasificacion = "Corriente media";
componentesOK++;
}
else
{
clasificacion = "ALTA CORRIENTE - Verificar";
componentesAdvertencia++;
}
reporteComponentes += string.Format(
"{0}: {1:F1}A - {2}\n",
id,
corriente,
clasificacion
);
}
reporteComponentes += string.Format(
"\nResumen: {0} OK, {1} con advertencia\n",
componentesOK,
componentesAdvertencia
);

¿Qué acabamos de hacer? Usamos for con índice para acceder simultáneamente a dos arrays paralelos (IDs y corrientes).


// ========================================
// PROCESAMIENTO 2: CALCULAR RESISTENCIAS
// ========================================
string reporteResistencias = "\n=== CÁLCULO DE RESISTENCIAS ===\n\n";
// Resistencias en serie (sumar todas)
double resistenciaTotalSerie = 0;
foreach (double resistencia in resistenciasSerie)
{
resistenciaTotalSerie += resistencia;
}
reporteResistencias += string.Format(
"Resistencia total en serie: {0:F2} Ω\n",
resistenciaTotalSerie
);
// Resistencias en paralelo (fórmula: 1/Rtotal = 1/R1 + 1/R2 + ...)
double sumaInversos = 0;
foreach (double resistencia in resistenciasSerie)
{
sumaInversos += 1.0 / resistencia;
}
double resistenciaTotalParalelo = 1.0 / sumaInversos;
reporteResistencias += string.Format(
"Resistencia total en paralelo: {0:F2} Ω\n",
resistenciaTotalParalelo
);
// Mostrar detalle de cada resistencia
reporteResistencias += "\nDetalle:\n";
int numeroResistencia = 1;
foreach (double resistencia in resistenciasSerie)
{
reporteResistencias += string.Format(
"R{0}: {1} Ω\n",
numeroResistencia,
resistencia
);
numeroResistencia++;
}

¿Qué acabamos de hacer? Usamos foreach para recorrer arrays sin necesidad de índices, ideal para sumas y cálculos acumulativos.


// ========================================
// PROCESAMIENTO 3: VALIDAR VOLTAJES
// ========================================
string reporteVoltajes = "\n=== VALIDACIÓN DE VOLTAJES ===\n\n";
double voltajeMinimo = 207.0; // 230V - 10%
double voltajeMaximo = 253.0; // 230V + 10%
int voltajesCorrectos = 0;
int voltajesIncorrectos = 0;
int indice = 0;
while (indice < voltajesMedidos.Length)
{
double voltaje = voltajesMedidos[indice];
if (voltaje >= voltajeMinimo && voltaje <= voltajeMaximo)
{
reporteVoltajes += string.Format(
"Punto {0}: {1:F1}V - OK\n",
indice + 1,
voltaje
);
voltajesCorrectos++;
}
else
{
reporteVoltajes += string.Format(
"Punto {0}: {1:F1}V - FUERA DE RANGO\n",
indice + 1,
voltaje
);
voltajesIncorrectos++;
}
indice++;
}
reporteVoltajes += string.Format(
"\nTotal: {0} correctos, {1} fuera de rango\n",
voltajesCorrectos,
voltajesIncorrectos
);

¿Qué acabamos de hacer? Usamos while con control manual del índice, útil cuando necesitas lógica más compleja dentro del bucle.


Paso 5: Calcular corriente total por tipo con bucles anidados

Sección titulada «Paso 5: Calcular corriente total por tipo con bucles anidados»
// ========================================
// PROCESAMIENTO 4: ANÁLISIS POR TIPO
// ========================================
string reporteTipos = "\n=== ANÁLISIS POR TIPO DE COMPONENTE ===\n\n";
// Tipos de componentes a buscar
string[] tiposComponentes = {"K", "Q", "F", "M"};
string[] nombresDescriptivos = {"Contactores", "Guardamotores", "Relés térmicos", "Motores"};
// Bucle externo: cada tipo de componente
for (int t = 0; t < tiposComponentes.Length; t++)
{
string tipo = tiposComponentes[t];
string nombre = nombresDescriptivos[t];
double corrienteTotal = 0;
int cantidad = 0;
// Bucle interno: cada componente en la lista
for (int i = 0; i < componentesID.Length; i++)
{
// Verificar si el componente es de este tipo
if (componentesID[i].StartsWith(tipo))
{
corrienteTotal += corrientes[i];
cantidad++;
}
}
if (cantidad > 0)
{
double corrientePromedio = corrienteTotal / cantidad;
reporteTipos += string.Format(
"{0}:\n" +
" Cantidad: {1}\n" +
" Corriente total: {2:F1}A\n" +
" Corriente promedio: {3:F1}A\n\n",
nombre,
cantidad,
corrienteTotal,
corrientePromedio
);
}
}

¿Qué acabamos de hacer? Usamos bucles anidados para agrupar componentes por tipo y calcular estadísticas.


Paso 6: Buscar componentes problemáticos con break

Sección titulada «Paso 6: Buscar componentes problemáticos con break»
// ========================================
// PROCESAMIENTO 5: DETECTAR PROBLEMAS
// ========================================
string reporteProblemas = "\n=== DETECCIÓN DE PROBLEMAS ===\n\n";
// Buscar primer componente con corriente excesiva
string primerProblematico = "";
double corrienteProblematica = 0;
double limite = 35.0; // A
for (int i = 0; i < componentesID.Length; i++)
{
if (corrientes[i] > limite)
{
primerProblematico = componentesID[i];
corrienteProblematica = corrientes[i];
break; // Encontramos el primero, no necesitamos seguir
}
}
if (primerProblematico != "")
{
reporteProblemas += string.Format(
"ADVERTENCIA: Componente {0} con corriente excesiva: {1:F1}A (límite: {2}A)\n",
primerProblematico,
corrienteProblematica,
limite
);
}
else
{
reporteProblemas += "Todos los componentes dentro de límites normales.\n";
}
// Contar componentes válidos (saltando los problemáticos con continue)
int componentesValidos = 0;
foreach (double corriente in corrientes)
{
if (corriente > limite)
{
continue; // Saltar este componente
}
componentesValidos++;
}
reporteProblemas += string.Format(
"Componentes válidos: {0} de {1}\n",
componentesValidos,
corrientes.Length
);

¿Qué acabamos de hacer? Usamos break para detener búsqueda cuando encontramos el primer problema, y continue para saltar elementos en el conteo.


// ========================================
// REPORTE FINAL
// ========================================
string separador = new string('=', 60);
string reporteFinal = string.Format(
"{0}\n" +
"PROCESADOR AUTOMÁTICO DE COMPONENTES ELÉCTRICOS\n" +
"{0}\n\n" +
"{1}\n" +
"{2}\n" +
"{3}\n" +
"{4}\n" +
"{5}\n\n" +
"{0}\n" +
"Procesamiento completado con {6} componentes\n" +
"{0}",
separador,
reporteComponentes,
reporteResistencias,
reporteVoltajes,
reporteTipos,
reporteProblemas,
componentesID.Length
);
// ========================================
// MOSTRAR RESULTADO
// ========================================
MessageBox.Show(reporteFinal, "Procesador de Componentes", MessageBoxButtons.OK, MessageBoxIcon.Information);

//
// Proyecto: Procesador Automático de Componentes Eléctricos
// Capítulo: 7
// Descripción: Demuestra uso de for, foreach, while, break, continue y bucles anidados
// Autor: C.D. López
// Fecha: Enero 2025
//
using System;
using Eplan.EplApi.Base;
using Eplan.EplApi.ApplicationFramework;
public class ProcesadorComponentes
{
[Start]
public void Ejecutar()
{
// ========================================
// DATOS DE ENTRADA
// ========================================
string[] componentesID = {"K1", "K2", "Q1", "Q2", "F1", "F2", "M1", "M2"};
double[] corrientes = {25.0, 40.0, 16.0, 20.0, 10.0, 16.0, 7.5, 11.0};
double[] resistenciasSerie = {100, 220, 330, 470, 560};
double[] voltajesMedidos = {232.5, 228.3, 235.1, 226.8, 230.2, 233.7};
// ========================================
// PROCESAMIENTO 1: VALIDAR COMPONENTES (FOR)
// ========================================
string reporteComponentes = "=== VALIDACIÓN DE COMPONENTES ===\n\n";
int componentesOK = 0;
int componentesAdvertencia = 0;
for (int i = 0; i < componentesID.Length; i++)
{
string id = componentesID[i];
double corriente = corrientes[i];
string clasificacion;
if (corriente < 16.0)
{
clasificacion = "Baja corriente";
componentesOK++;
}
else if (corriente <= 32.0)
{
clasificacion = "Corriente media";
componentesOK++;
}
else
{
clasificacion = "ALTA CORRIENTE - Verificar";
componentesAdvertencia++;
}
reporteComponentes += string.Format("{0}: {1:F1}A - {2}\n", id, corriente, clasificacion);
}
reporteComponentes += string.Format("\nResumen: {0} OK, {1} con advertencia\n", componentesOK, componentesAdvertencia);
// ========================================
// PROCESAMIENTO 2: CALCULAR RESISTENCIAS (FOREACH)
// ========================================
string reporteResistencias = "\n=== CÁLCULO DE RESISTENCIAS ===\n\n";
double resistenciaTotalSerie = 0;
foreach (double resistencia in resistenciasSerie)
{
resistenciaTotalSerie += resistencia;
}
reporteResistencias += string.Format("Resistencia total en serie: {0:F2} Ω\n", resistenciaTotalSerie);
double sumaInversos = 0;
foreach (double resistencia in resistenciasSerie)
{
sumaInversos += 1.0 / resistencia;
}
double resistenciaTotalParalelo = 1.0 / sumaInversos;
reporteResistencias += string.Format("Resistencia total en paralelo: {0:F2} Ω\n", resistenciaTotalParalelo);
reporteResistencias += "\nDetalle:\n";
int numeroResistencia = 1;
foreach (double resistencia in resistenciasSerie)
{
reporteResistencias += string.Format("R{0}: {1} Ω\n", numeroResistencia, resistencia);
numeroResistencia++;
}
// ========================================
// PROCESAMIENTO 3: VALIDAR VOLTAJES (WHILE)
// ========================================
string reporteVoltajes = "\n=== VALIDACIÓN DE VOLTAJES ===\n\n";
double voltajeMinimo = 207.0;
double voltajeMaximo = 253.0;
int voltajesCorrectos = 0;
int voltajesIncorrectos = 0;
int indice = 0;
while (indice < voltajesMedidos.Length)
{
double voltaje = voltajesMedidos[indice];
if (voltaje >= voltajeMinimo && voltaje <= voltajeMaximo)
{
reporteVoltajes += string.Format("Punto {0}: {1:F1}V - OK\n", indice + 1, voltaje);
voltajesCorrectos++;
}
else
{
reporteVoltajes += string.Format("Punto {0}: {1:F1}V - FUERA DE RANGO\n", indice + 1, voltaje);
voltajesIncorrectos++;
}
indice++;
}
reporteVoltajes += string.Format("\nTotal: {0} correctos, {1} fuera de rango\n", voltajesCorrectos, voltajesIncorrectos);
// ========================================
// PROCESAMIENTO 4: ANÁLISIS POR TIPO (BUCLES ANIDADOS)
// ========================================
string reporteTipos = "\n=== ANÁLISIS POR TIPO DE COMPONENTE ===\n\n";
string[] tiposComponentes = {"K", "Q", "F", "M"};
string[] nombresDescriptivos = {"Contactores", "Guardamotores", "Relés térmicos", "Motores"};
for (int t = 0; t < tiposComponentes.Length; t++)
{
string tipo = tiposComponentes[t];
string nombre = nombresDescriptivos[t];
double corrienteTotal = 0;
int cantidad = 0;
for (int i = 0; i < componentesID.Length; i++)
{
if (componentesID[i].StartsWith(tipo))
{
corrienteTotal += corrientes[i];
cantidad++;
}
}
if (cantidad > 0)
{
double corrientePromedio = corrienteTotal / cantidad;
reporteTipos += string.Format("{0}:\n Cantidad: {1}\n Corriente total: {2:F1}A\n Corriente promedio: {3:F1}A\n\n",
nombre, cantidad, corrienteTotal, corrientePromedio);
}
}
// ========================================
// PROCESAMIENTO 5: DETECTAR PROBLEMAS (BREAK/CONTINUE)
// ========================================
string reporteProblemas = "\n=== DETECCIÓN DE PROBLEMAS ===\n\n";
string primerProblematico = "";
double corrienteProblematica = 0;
double limite = 35.0;
for (int i = 0; i < componentesID.Length; i++)
{
if (corrientes[i] > limite)
{
primerProblematico = componentesID[i];
corrienteProblematica = corrientes[i];
break;
}
}
if (primerProblematico != "")
{
reporteProblemas += string.Format("ADVERTENCIA: Componente {0} con corriente excesiva: {1:F1}A (límite: {2}A)\n",
primerProblematico, corrienteProblematica, limite);
}
else
{
reporteProblemas += "Todos los componentes dentro de límites normales.\n";
}
int componentesValidos = 0;
foreach (double corriente in corrientes)
{
if (corriente > limite)
{
continue;
}
componentesValidos++;
}
reporteProblemas += string.Format("Componentes válidos: {0} de {1}\n", componentesValidos, corrientes.Length);
// ========================================
// REPORTE FINAL
// ========================================
string separador = new string('=', 60);
string reporteFinal = string.Format(
"{0}\n" +
"PROCESADOR AUTOMÁTICO DE COMPONENTES ELÉCTRICOS\n" +
"{0}\n\n" +
"{1}\n{2}\n{3}\n{4}\n{5}\n\n" +
"{0}\n" +
"Procesamiento completado con {6} componentes\n" +
"{0}",
separador, reporteComponentes, reporteResistencias, reporteVoltajes,
reporteTipos, reporteProblemas, componentesID.Length
);
MessageBox.Show(reporteFinal, "Procesador de Componentes", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
}

Cómo probar el script:

  1. Guarda en: X:\Scripts\v6.0\ProcesadorComponentes.cs
  2. Ejecuta en EPLAN
  3. Ver reporte completo con todos los análisis

Ejercicios:

  • Agrega más componentes a los arrays
  • Cambia los valores de corriente para ver advertencias
  • Agrega voltajes fuera de rango
  • Modifica las resistencias y observa los cálculos

for vs foreach - ¿Cuál es más rápido?

Para arrays simples, for es ligeramente más rápido, pero la diferencia es despreciable en la mayoría de casos.

// for: acceso directo por índice
for (int i = 0; i < array.Length; i++)
{
var item = array[i];
}
// foreach: usa enumerador interno
foreach (var item in array)
{
// Ligeramente más lento, pero más legible
}

Recomendación: Usa foreach por defecto (más legible). Usa for solo cuando necesites el índice o performance crítica.

En algunos casos, bucles infinitos son intencionales:

while (true)
{
// Procesar algo...
if (condicionSalida)
{
break; // Salida controlada
}
}

Uso en EPLAN: Monitorear estado hasta que usuario cancele.

Malo (ineficiente):

for (int i = 0; i < 1000; i++)
{
for (int j = 0; j < 1000; j++)
{
// 1,000,000 iteraciones
string resultado = ExpensiveOperation();
}
}

Mejor (optimizado):

string resultado = ExpensiveOperation(); // Solo una vez
for (int i = 0; i < 1000; i++)
{
for (int j = 0; j < 1000; j++)
{
// Usar resultado pre-calculado
}
}

1. Nombres descriptivos para variables de bucle

// Mal
for (int i = 0; i < c.Length; i++)
{
// ¿Qué es i? ¿Qué es c?
}
// Bien
for (int indiceComponente = 0; indiceComponente < componentes.Length; indiceComponente++)
{
// Claro y legible
}
// Aceptable para bucles simples
for (int i = 0; i < items.Length; i++)
{
// 'i' es estándar para índices
}

2. Evita modificar contador dentro del bucle

// Mal (confuso)
for (int i = 0; i < 10; i++)
{
if (condicion)
{
i += 2; // Modificar el contador puede causar bugs
}
}
// Bien
for (int i = 0; i < 10; i++)
{
if (condicion)
{
continue; // Saltar iteraciones específicas
}
}

3. Caché la longitud si es costosa

// Ineficiente (calcula Length en cada iteración si es costoso)
for (int i = 0; i < MetodoComplejo().Length; i++)
{
// ...
}
// Eficiente
int longitud = MetodoComplejo().Length;
for (int i = 0; i < longitud; i++)
{
// ...
}
int[] numeros = {10, 20, 30, 40, 50};
// Mal: va de 0 a 5 (¡índice 5 no existe!)
for (int i = 0; i <= numeros.Length; i++) // ERROR
{
MessageBox.Show(numeros[i].ToString());
}
// Bien: va de 0 a 4
for (int i = 0; i < numeros.Length; i++)
{
MessageBox.Show(numeros[i].ToString());
}

Error 2: Modificar colección durante foreach

Sección titulada «Error 2: Modificar colección durante foreach»
List<string> componentes = new List<string>{"K1", "Q1", "F1"};
// ERROR: No puedes modificar la colección durante foreach
foreach (string comp in componentes)
{
componentes.Remove(comp); // ERROR en tiempo de ejecución
}
// Solución: Usa for hacia atrás
for (int i = componentes.Count - 1; i >= 0; i--)
{
componentes.RemoveAt(i); // OK
}

int contador = 0;
// Bucle infinito (nunca termina)
while (contador < 10)
{
MessageBox.Show("Contador: " + contador);
// ¡Olvidaste incrementar!
}
// Correcto
while (contador < 10)
{
MessageBox.Show("Contador: " + contador);
contador++; // ← Esencial
}

Desafío 1: Generador de secuencia Fibonacci

Sección titulada «Desafío 1: Generador de secuencia Fibonacci»

Dificultad: ⭐⭐☆

Genera los primeros 10 números de la secuencia Fibonacci (1, 1, 2, 3, 5, 8, 13, 21, 34, 55) usando un bucle for.

Pista

Necesitas dos variables para almacenar los dos números anteriores, y en cada iteración calculas el siguiente sumando los dos anteriores.


Desafío 2: Calculadora de costos por tipo de componente

Sección titulada «Desafío 2: Calculadora de costos por tipo de componente»

Dificultad: ⭐⭐☆

Tienes arrays de: componentesID, tiposComponente (K, Q, F, M), precios. Calcula el costo total por cada tipo de componente usando bucles anidados.


Desafío 3: Validador de proyecto con múltiples criterios

Sección titulada «Desafío 3: Validador de proyecto con múltiples criterios»

Dificultad: ⭐⭐⭐

Crea un script que procese una lista de páginas del proyecto y valide:

  • Páginas numeradas correctamente (secuencia 1, 2, 3…)
  • Páginas sin nombre (error)
  • Páginas duplicadas

Usa diferentes tipos de bucles según convenga y genera reporte detallado.


En este capítulo aprendiste:

  • Bucle for: Para repetir un número conocido de veces
  • Bucle foreach: Para iterar colecciones sin índices
  • Bucle while: Para repetir mientras se cumpla condición
  • Bucle do-while: Para ejecutar al menos una vez
  • break y continue: Para controlar flujo dentro de bucles
  • Bucles anidados: Para estructuras bidimensionales
  • Proyecto construido: Procesador automático de componentes con múltiples análisis

Conceptos clave:

  • Los bucles eliminan código repetitivo
  • Elige el tipo de bucle según la situación
  • Cuidado con bucles infinitos
  • break sale del bucle, continue salta a la siguiente iteración
  • Los bucles anidados multiplican iteraciones

Capítulo 6: Control de flujo - switch

Capítulo 8: Funciones (métodos)

En el próximo capítulo aprenderás a organizar tu código en bloques reutilizables llamados funciones. Verás cómo dividir problemas complejos en funciones más simples, pasar parámetros, devolver valores, y construir una librería de funciones para cálculos eléctricos.



R: Usa foreach cuando solo necesites recorrer todos los elementos (más simple y legible). Usa for cuando necesites el índice, quieras saltar elementos, o modificar el array.

P: ¿Puedo usar break en un bucle anidado para salir de ambos?

Sección titulada «P: ¿Puedo usar break en un bucle anidado para salir de ambos?»

R: No, break solo sale del bucle más interno. Para salir de ambos, usa una variable bandera o una función con return.

P: ¿Qué pasa si el array está vacío en un foreach?

Sección titulada «P: ¿Qué pasa si el array está vacío en un foreach?»

R: El bucle simplemente no ejecuta ninguna iteración (no da error).

P: ¿Cuántos niveles de anidación son recomendables?

Sección titulada «P: ¿Cuántos niveles de anidación son recomendables?»

R: Máximo 2-3 niveles. Si necesitas más, considera refactorizar usando funciones.

R: No, es el menos común. Se usa principalmente para menús que deben mostrarse al menos una vez, o validaciones que deben ejecutarse mínimo una vez.


Antes de pasar al siguiente capítulo, asegúrate de:

  • Entender la diferencia entre for, foreach, while y do-while
  • Saber cuándo usar cada tipo de bucle
  • Poder usar break y continue correctamente
  • Entender cómo funcionan los bucles anidados
  • Haber ejecutado exitosamente el procesador de componentes
  • Poder modificar los arrays de entrada y ver diferentes resultados
  • Evitar bucles infinitos accidentales
  • (Opcional) Haber intentado al menos un desafío

¿Listo para aprender a crear funciones reutilizables? Vamos al Capítulo 8! 🚀


Última actualización: Enero 2025 Tiempo de lectura estimado: 50-60 minutos Código de ejemplo: code/cap-07/

Todos los scripts de este capítulo están disponibles en GitHub:

📥 Ver código en GitHub →

Los scripts son 100% funcionales y usan únicamente APIs gratuitas de EPLAN.


🔓 Desbloquea el Contenido Completo

¿Te gustó este capítulo? Hay 25 capítulos más esperándote con:

  • ✅ Scripts profesionales completos
  • ✅ Casos de estudio reales
  • ✅ Suite de automatización integrada
  • ✅ Ahorra 80-95% de tiempo en tareas repetitivas