Inicializadores de objetos en una consulta LINQ: ¿es posible reutilizar los datos calculados?

StackOverflow https://stackoverflow.com/questions/6331913

  •  27-10-2019
  •  | 
  •  

Pregunta

Estoy usando una consulta linq que se ve (después de alguna simplificación) similar a la siguiente:

List<UserExams> listUserExams = GetUserExams();

var examData = 
from userExam in listUserExams
group by userExam.ExamID into groupExams
select new ExamData()
{
    ExamID = groupExams.Key,
    AverageGrade = groupExams.Average(e => e.Grade),
    PassedUsersNum = groupExams.Count(e => /* Some long and complicated calculation */),
    CompletionRate = 100 * groupExams.Count(e => /* The same long and complicated calculation */) / TotalUsersNum
};

Lo que me molesta es la expresión de cálculo que aparece dos veces, para PassedUsersNum y CompletionRate.

Suponiendo que CompletionRate = (PassedUsersNum / TotalUsersNum) * 100, ¿cómo puedo escribirlo reutilizando el cálculo de PassedUsersNum, en lugar de escribir esa expresión de nuevo?

¿Fue útil?

Solución

La forma más sencilla sería utilizar let para inyectar otro paso de selección primero:

List<UserExams> listUserExams = GetUserExams();

var examData = 
    from userExam in listUserExams
    group by userExam.ExamID into groupExams
    let passCount = groupExams.Count( /* long expression */)
    select new ExamData()
    {
        ExamID = groupExams.Key,
        AverageGrade = groupExams.Average(e => e.Grade),
        PassedUsersNum = passCount,
        CompletionRate = 100 * passCount / TotalUsersNum
    };

La expresión solo se evaluará una vez por grupo, por supuesto.

Otros consejos

También puede simplemente extraer su función Count en otro método que devuelva un Func si lo desea, o un método que toma un doble y devuelve un bool.

List<UserExams> listUserExams = GetUserExams();

var examData = 
from userExam in listUserExams
group by userExam.ExamID into groupExams
select new ExamData()
{
    ExamID = groupExams.Key,
    AverageGrade = groupExams.Average(funcMethod()),
    PassedUsersNum = groupExams.Count(e => traditionalMethod(e)),
    CompletionRate = 100 * groupExams.Count(e => /* The same long and complicated calculation */) / TotalUsersNum
};

// later...
private Func<double,bool> funcMethod(){ return e=> /* your calculation */ }

private bool traditionalMethod(double d){ return /* your calculation */ }
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top