Domina el cálculo de promedios por asignatura en C# con un enfoque claro: usar LINQ para agrupar evaluaciones, añadir resultados a un diccionario y evitar tipos anónimos creando una clase específica. Verás por qué depender de object y casting complica el trabajo y cómo una estructura tipada hace el código más legible, seguro y mantenible.
¿Cómo agregar promedios de alumnos al diccionario de respuesta?
Para organizar la salida se renombra la lista como promediosAlumnos y se adiciona al diccionario de respuesta usando como key el nombre de la asignatura. La clave representa la asignatura, y el valor es la lista de promedios de sus alumnos.
Usar un diccionario con key string para la asignatura.
Guardar listas de promedios de alumnos como value.
Validar que la key sea el nombre de la asignatura.
// Ejemplo de estructura de cargavar promediosAlumnos =newList<AlumnoPromedio>();respuesta.Add(asignaturaNombre, promediosAlumnos);
¿Qué clave usar en el diccionario por asignatura?
La key es el nombre de la asignatura.
Evita claves ambiguas: usa el nombre exacto de la asignatura.
Asegura unicidad por asignatura para consultar sin errores.
¿Cómo iterar los pares key-value con foreach?
Al recorrer la estructura, usa item.Key para la asignatura e item.Value para la lista de alumnos con promedio.
Diferencia claramente asignatura, ID de alumno y promedio.
foreach(var item in listaPromediosPorAsignatura){var asignatura = item.Key;// nombre de la asignaturavar alumnosConPromedio = item.Value;// List<AlumnoPromedio>}
¿Por qué evitar tipos anónimos y usar una clase AlumnoPromedio?
Cuando la lista interna usa tipos anónimos, el sistema la trata como object. Al intentar acceder a propiedades, no hay ayuda del compilador y terminas haciendo casting, lo que es frágil y propenso a fallos si la implementación cambia. En su lugar, define una clase concreta.
Los tipos anónimos son locales al método.
Fuera del método, solo quedan como object.
El casting con as requiere comprobaciones de nulos y añade complejidad.
¿Qué problema causa object y casting en tiempo de ejecución?
No hay acceso directo a propiedades.
Alto riesgo de errores si cambia la forma de los datos.
foreach(var alum in item.Value){var tmp = alum asAlumno;// puede ser nullif(tmp !=null){// Acceso a propiedades, pero con riesgo y ruido.}}
¿Cómo definir AlumnoPromedio y mapear propiedades?
Se crea un tipo fuerte y simple. Se discutió el encapsulamiento, pero para el ejercicio se dejó como campos públicos para reducir sobrecarga.
publicclassAlumnoPromedio{publicfloat promedio;publicstring alumnoId;publicstring alumnoNombre;// se llena al enriquecer el grupo}
promedio: promedio final del alumno en la asignatura.
alumnoId: identifica al alumno de forma estable.
alumnoNombre: se agrega para lectura humana.
var ap =newAlumnoPromedio{ alumnoId = keyAlumno,// obtenido del agrupamiento alumnoNombre = nombreAlumno,// enriquecido en el grupo promedio = promedioCalculado
};
¿Cómo usar LINQ para agrupar por asignatura y calcular promedios?
La clave está en agrupar por asignatura y, dentro del grupo, generar una clave compuesta con ID de alumno y nombre para poder poblar ambos valores. Así se evita depender de datos fuera del grupo y se completa AlumnoPromedio correctamente.
Agrupar por asignatura y por alumno con clave compuesta.
Calcular el promedio con las notas del grupo.
Mapear a AlumnoPromedio y adicionar al diccionario.
var consulta = evaluaciones
.GroupBy(eval =>new{ asignatura = eval.Asignatura.Nombre, uniqueId = eval.Alumno.Id, nombre = eval.Alumno.Nombre
}).Select(g =>new{ g.Key.asignatura, alumno =newAlumnoPromedio{ alumnoId = g.Key.uniqueId, alumnoNombre = g.Key.nombre, promedio = g.Average(e => e.Nota)}});// Ensamblar el diccionario final por asignaturavar respuesta =newDictionary<string, List<AlumnoPromedio>>();foreach(var item in consulta){if(!respuesta.TryGetValue(item.asignatura,outvar lista)){ lista =newList<AlumnoPromedio>(); respuesta[item.asignatura]= lista;} lista.Add(item.alumno);}
¿Qué consultas LINQ se aplicaron con keywords?
from, select, where: para proyectar y filtrar datos.
group by: para agrupar por asignatura y alumno.
distinct: para eliminar duplicados donde correspondía.
order by: ya utilizado en ejercicios previos para ordenar listas.
¿Qué se validó en el resultado final?
Asignaturas como Matemáticas y Castellano con su lista de alumnos.
Cada entrada con alumnoNombre, alumnoId y promedio.
Comprobación visual de nombres y promedios cargados correctamente.
¿Te gustaría que preparemos una variante que incluya ordenamiento por promedio o filtros por asignatura específica? Deja tus dudas o ideas en los comentarios y armamos la siguiente mejora juntos.