Bucles anidados para crear evaluaciones masivas en C#
Resumen
Crear evaluaciones automáticas por curso, asignatura y alumno es más simple de lo que parece si dominas bucles anidados, nombres únicos y números aleatorios. Aquí verás cómo generar cinco evaluaciones por alumno, nombrarlas de forma clara y calcular notas decimales entre 0 y 5 con Random, paso a paso y sin complicaciones.
¿Cómo recorrer cursos, asignaturas y alumnos para crear evaluaciones?
Para cumplir el objetivo, se recorre la estructura académica con bucles anidados y se generan cinco evaluaciones por alumno en cada asignatura. La clave es pensar primero en el conjunto completo de objetos que se deben crear y luego iterar siguiendo ese orden lógico.
Por cada curso en la escuela.
Por cada asignatura del curso.
Por cada alumno del curso.
Crear cinco evaluaciones por alumno.
Ejemplo en C# usando foreach y for:
foreach(var curso in escuela.Cursos){foreach(var asignatura in curso.Asignaturas){foreach(var alumno in curso.Alumnos){// Semilla por alumno para el generador aleatoriovar rnd =newRandom(System.Environment.TickCount);for(int i =0; i <5; i++){// Se completará con nombre y nota más abajo}}}}
Puntos clave:
Cinco evaluaciones por alumno. Requisito explícito del reto.
Orden de iteración: curso → asignatura → alumno → cinco evaluaciones.
Inicializar Random por alumno. Controla la semilla y facilita la variación de notas.
¿Cómo asignar nombres únicos y legibles a las evaluaciones?
El nombre debe ser único y comprensible. En lugar de iniciar desde 0, se usa un índice humano-amigable desde 1. Se concatena el nombre de la asignatura con un postfijo "Ev" y el consecutivo.
Evita repeticiones de nombre.
Mejora la legibilidad para usuarios no programadores.
Mantiene un patrón consistente.
Ejemplo:
var nombreEv =$"{asignatura.Nombre} Ev{(i +1)}";// p.ej., "Matemáticas Ev1"
Buenas prácticas:
Coherencia de formato. Siempre "Asignatura EvN".
Sin ceros iniciales. Empieza en 1 para el usuario final.
¿Cómo generar notas decimales de 0 a 5 con Random?
Usar rnd.Next(0, 5) sería un error: genera enteros, no decimales. La solución es rnd.NextDouble(), que produce un decimal en [0, 1). Luego se escala y se hace casting al tipo requerido.
*Next* devuelve enteros en un rango. No sirve para decimales.
*NextDouble* devuelve decimales entre 0 y 1.
Multiplicar por 5 ajusta el rango a [0, 5].
Casting a float si la nota es flotante en el modelo.
Código recomendado:
// Genera una nota decimal entre 0 y 5double nota0a5 = rnd.NextDouble()*5;// double por precisiónfloat nota =(float)nota0a5;// casting a float si la propiedad es flotante
¿Cómo inicializar la semilla por alumno con System.Environment.TickCount?
Para mostrar control sobre la aleatoriedad, se puede variar la semilla por alumno con System.Environment.TickCount. Así se crea una nueva instancia de Random por alumno, asignatura y curso.
var rnd =newRandom(System.Environment.TickCount);
Ventajas:
Semilla controlada. Permite reproducibilidad si se necesita.
Variación suficiente. Cambia entre alumnos y recorridos.
¿Cómo validar con el depurador y foreach en Visual Studio?
El flujo se verifica con un punto de interrupción en el foreach y revisando el objeto de evaluación en el inspector de variables.
Colocar el breakpoint en el bucle que crea las evaluaciones.
Inspeccionar nombreEv y nota en cada iteración.
Verificar secuencia: Ev1, Ev2, Ev3, Ev4, Ev5.
Confirmar rangos: notas entre 0 y 5 con decimales.
Ejemplo de creación integrada:
for(int i =0; i <5; i++){var nombreEv =$"{asignatura.Nombre} Ev{(i +1)}";float nota =(float)(rnd.NextDouble()*5);var ev =newEvaluacion{ Asignatura = asignatura, Alumno = alumno, Nombre = nombreEv, Nota = nota
};// Agregar a la colección correspondiente (p. ej., alumno.Evaluaciones.Add(ev));}
Comparte tus aproximaciones, incluso si son distintas o menos eficientes. Lo valioso es que todos aprendamos juntos. ¿Qué parte te resultó más desafiante y cómo la resolviste?
Finalmente estoy confirmando que hay mucha improvisación. Parece un despropósito que de clase en clase aparezcan cosas que no se han hecho, que no se han visto en los videos. En este caso, la clase Alumno no tenia un propiedad Evaluaciones, que "mágicamente" aparece cuando en este video se explica la solución dada por el instructor. Una perdida enorme de tiempo revisando la creacion de las clases. Intento seguir positivo, pero para quienes estamos acá, en fundamentos, realmente es frustrante. un pena que las cosas sean así. Ademas, utiliza nombres que no son los correctos, y en el video no marca un error, como por ejemplo new Evaluacion. Cual clase de llama así?
Desde mi punto de vista el curso no es tan basico, ya que se requiere otros conocimiento o ya supone que tu lo sabes.
Muy de acuerdo con el punto de vista, no tiene un orden o control del curso, lo hace al paso cada cosa, no tiene un plan o estructura de que va a dar primero y mucho menos seguir los propios conceptos impartidos, de fundamentos no tiene nada porque los conceptos que está viendo son intermedio y avanzados deberían cambiar de profesor.
En este video no salió pero la clase "Alumno" se debe ver asi:
No se especificó en el vídeo pero a la clase Alumno se le agregó la propiedad de lista de evaluaciones.
Yo lo agregué a la clase Asignatura.
Por lo demás, casi todo igual salvo la generación del random.
Gracias! tuve que recorrer los videos donde creó las entidades y vi que nunca le dio ese atributo a la clase alumnos, asi que la creé. Ahora tu comentario me confirma que no estoy loco y que estoy entendiendo almenos un poco
Gracias por el dato
Modelo Datos
Solución
Este modelo de datos, está mal implementado, porque si luego miras la propiedad de la clase asignatura cuando se cargan los cursos solamente están cargando en estudiante y asignatura también debería de tener evaluaciones, según tu modelo. Creo que debería de quitar del modelo la relación de asignaturas con evaluaciones.
S.O.S
No pude aprovechar el curso, y me frustra por que la solución final del reto no se explicó ni se mostró como deberia @JuanCarlosRuiz. Me gustó la forma en la que explicó durante el curso.
@TeamPlatzi alguno me puede ayudar a terminar mi solución o ver si se puede subir aquí la solución de JuanCarlosRuiz??
Saludos
Reto:
privatevoidgenerarEvaluaciones(){Random rnd =newRandom();foreach(var curso inColegio.Cursos){foreach(var materia in curso.Asignaturas){foreach(var estudiante in curso.Alumnos){ float calificacion =(rnd.Next(0,5)*1.0f)+(rnd.Next(0,9)/10.0f);var evaluacion =newEvaluacion("Corte1",calificacion,estudiante,materia);WriteLine($"{estudiante.Nombre} - {materia.Nombre} -{evaluacion.Nombre}: {evaluacion.Nota}");}}}}
Me pase de infantil con los nombres jajajajajaja!
S.O.S
No pude aprovechar el curso, y me frustra por que la solución final del reto no se explicó ni se mostró como deberia @JuanCarlosRuiz. Me gustó la forma en la que explicó durante el curso.
@TeamPlatzi alguno me puede ayudar a terminar mi solución o ver si se puede subir aquí la solución de JuanCarlosRuiz??
Saludos
Si aún tienes problemas te puedo ayudar Branyan, puedes subir el proyecto a un repo de github y me pasas la url
Para solucionar lo de la nota, lo hice generando un random entre 0 y 50 y casteando la división por 10
Random rand =newRandom();float nota =(float)(rand.Next(0,50)/10.0);WriteLine(nota);
****Todavía podría mejorar un poco mi solución pero al menos cumple, primero añadí una lista de evaluaciones a la clase Curso
Despues crear un metodo para generar las evaluaciones, puedo indicar cuantas evaluaciones se van a generar por materia, por defecto 1 , aqui ademas se llama a un metodo que genera las notas al azar
Para visualizar genere un método que imprime las notas de los alumnos y un resumen del curso y cantidad de alumnos.
Trate de hacer un filtrado en la lista pero es probable que esto este de mas o se pueda mejorar bastante.
Resultado Final
****
Muchisimas gracias hermano, me estaba preguntando de que forma estaria bien hacerlo
Hola amigos acá dejo mi repo con la solución
gracias amigo, creo que me acostumbre mas a los nombres in ingles hahahahaha
Excelente curso, un poco denso pero muy valioso. Solo una observación... seria genial que desde el principio de la clase se hubiera diseñado todo el programa para saber que se iba a codear...Esta última clase existieron modificaciones en las clases y en los atributos como por ejemplo alumno.
privatevoidCargarEvaluaciones(){Random rnd =newRandom();foreach(var curso inEscuela.Cursos){foreach(var materia in curso.Asignaturas){foreach(var alumno in curso.Alumnos){for(int i =0; i <5; i++){var evaluacion =newEvaluaciones(){Alumno= alumno,Asignatura= materia,Nota=(rnd.Next(0,5)*1.0f)+(rnd.Next(0,9)/10.0f),Nombre= $"Evaluación {i + 1} {materia.Nombre}"}; alumno.Evaluaciones.Add(evaluacion);}}}}}
Yo implementé al final una función en la clase printer, para poder imprimir la información de la escuela. Ordenada por curso, alumno y materia. Mostrando sus evaluaciones y su promedio por materia.
internal staticvoidImprimirInformacionEscuela(Escuela escuela){DibujarTitulo(escuela.Nombre);WriteLine($"{escuela.AñoCreacion}, {escuela.Ciudad}, {escuela.Pais}");foreach(var c in escuela.cursos){WriteLine($"{c.Nombre} - {c.id}");foreach(var a in c.Alumnos){WriteLine($"{a.Nombre} - {a.UniqueId}");foreach(var m in c.Asignaturas){WriteLine($"{m.Nombre}"); float promedio =0;foreach(var e in m.Evaluaciones){if(e.Alumno.UniqueId==a.UniqueId){WriteLine($"{e.Nombre}: {e.Nota}"); promedio+=e.Nota;}} promedio=promedio/5;WriteLine($"Promedio: {promedio}");}DibujarLinea(50);}}}
Para validar sólo los 2 dígitos decimales para la Notade cada Evaluacion yo usé lo siguiente: