2016-07-29 3 views
-2

У меня есть List = new List();Поиск максимального значения в linq

public class Student 
{ 
    public string Id { get; set; } 
    public string name { get; set; } 
    public string subject { get; set; } 
    public string marks { get; set; } 
} 

Моя цель

Найти студента с самым высоким средним

Добавление выборки данных

i.Add(new List<Student> { Id=1,Name= "Maddy",Subject="English",Marks=87 }; 
i.Add(new List<Student> { Id=1,Name= "Maddy",Subject="Science",Marks=81 }; 
i.Add(new List<Student> { Id=2,Name= "Mathew",Subject="Maths",Marks=83 }; 
i.Add(new List<Student> { Id=2,Name= "Mathew",Subject="Science",Marks=80 }; 

Что я пытался

var x= i.GroupBy(i=>i.Id) 
     .Select(g=> new 
        { 
         MaxAverage= g.Max(g.Average(i=>i.Marks)) 
         } 
+0

Как намек, вы хотите работать в среднем для каждого студента, а затем выбрать первый из студентов Упорядочены по их среднему значению. –

+0

Является ли 'mark'' строкой' или 'int'? Каким должен быть результат, идентификатор студента или имя или что? –

+1

Вы должны попытаться сделать это без Linq first – Sehnsucht

ответ

2
  • Использование Linq "синтаксис запроса"

    var best = from student in students 
          group student by student.Id into studentAverage 
          let average = studentAverage.Average (s => s.Marks) 
          orderby average descending 
          select new { id = studentAverage.Key, average }; 
          // change projection to have only id or average 
    
  • Использование Linq "метод синтаксис"

    var best = 
        students 
        .GroupBy (student => student.Id, 
           student => student.Marks, 
           (id, marks) => new { id, average = marks.Average() }) 
        .OrderByDescending (studentAverage => studentAverage.average) 
        // add a projection (Select) here to have only id or average 
        .FirstOrDefault(); 
    

    Может быть простая альтернатива, но более ориентированы на получение только Id

    var best = 
        students 
        .ToLookup (s => s.Id, s => s.Marks) 
        .OrderByDescending (marksById => marksById.Average()) 
        .FirstOrDefault(); 
    
    // Key will contain the Id but Average must be calculated again 
    // var avg = best.Average(); 
    
  • Использование «классического» кода (дольше, но более четкие шаги)

    var studentMarks = new Dictionary<int, List<double>> (students.Count); 
    
    foreach (var student in students) 
    { 
        int id = student.Id; 
        List<double> marks; 
    
        if (!studentMarks.TryGetValue (id, out marks)) 
        { 
         marks = new List<double>(); 
         studentMarks.Add (id, marks); 
        } 
    
        marks.Add (student.Marks); 
    } 
    
    double? bestAverage = null; 
    int? idOfBest = null; 
    
    foreach (var idAndMarks in studentMarks) 
    { 
        var average = 0.0; 
    
        foreach (var mark in idAndMarks.Value) 
        { 
         average += mark; 
        } 
    
        average /= idAndMarks.Value.Count; 
    
        if (average > bestAverage) 
        { 
         bestAverage = average; 
         idOfBest = idAndMarks.Key; 
        } 
    } 
    
+0

вам нужно будет обновить блок if в первом foreach с этим ... 'studentMarks.Add (id, marks = new List ())' ... иначе вы получите исключения из меток, которые не устанавливаются на первый проход для каждого нового идентификатора. –

+0

@MatthewWhited thx для этого недостающего бита ;-) – Sehnsucht

0
var i = new List<Student>(); 

i.Add(new Student { Id = 1, Name = "Maddy", Subject = "English", Marks = 87 }); 
i.Add(new Student { Id = 1, Name = "Maddy", Subject = "Science", Marks = 81 }); 
i.Add(new Student { Id = 2, Name = "Mathew", Subject = "Maths", Marks = 83 }); 
i.Add(new Student { Id = 2, Name = "Mathew", Subject = "Science", Marks = 80 }); 


var students = i.GroupBy(p => p.Id).ToDictionary(group => group.Key, group => group.Select(p => p.Marks).Average()); 
var maxStudent = students.Aggregate((l, r) => l.Value > r.Value ? l : r).Key; 
2

Лучший студент

var best = i.GroupBy(g => g.Id) 
      .Select(g => new { 
       StudentID = g.Key, 
       Name = g.First().Name, 
       Average = g.Average(m => m.Marks), 
       }) 
      .OrderByDescending(g => g.Average) 
      .First(); 
// best = { StudentID = 1, Name = Maddy, Average = 84 } 

Лучшие Средняя

var best = i.GroupBy(g => g.Id) 
      .Select(g => g.Average(m => m.Marks)) 
      .Max(); 
// best = 84.0 

Синтаксис запросов (только потому, что)

var best = (from student in 
       from grade in grades 
       group grade by grade.Id 
      select student.Average(mark=>mark.Marks)).Max();  
// best = 84.0 

Без LINQ (я видел комментарий предлагаю вам сделать это таким образом ... ОЙ)

var dict = new Dictionary<int, List<double>>(); 
foreach (var g in i) 
{ 
    var id = g.Id; 
    if (!dict.ContainsKey(id)) 
     dict.Add(id, new List<double>()); 
    dict[id].Add(g.Marks); 
} 
double best = 0.0; 
foreach (var g in dict) 
{ 
    var totalmarks = 0.0; 
    foreach (var mark in g.Value) 
    { 
     totalmarks += (double)mark; 
    } 
    var average = totalmarks/g.Value.Count; 
    if (best < average) 
     best = average; 
} 
// best = 84.0 

Без LINQ (немного оптимизированный)

var dict = new Dictionary<int, Tuple<int, double>>(); 
foreach (var g in i) 
{ 
    var id = g.Id; 
    Tuple<int, double> t; 
    if (!dict.ContainsKey(id)) 
     dict.Add(id, t = Tuple.Create(0, 0.0)); 
    else 
     t = dict[id]; 
    var c = t.Item1 + 1; 

    dict[id] = Tuple.Create(c, (t.Item2 * t.Item1 + g.Marks)/c); 
} 
double best = 0.0; 
foreach (var g in dict) 
{ 
    var m = g.Value.Item2; 
    if (best < m) 
     best = m; 
} 
// best = 84.0 
+0

Недопустимая версия синтаксиса запроса. Вы делаете проекцию после группы, поэтому вам нужно дать имя группе и использовать ее. –

+0

Вы уверены? Он работает правильно. –

+1

О, как вы его написали, я полагаю, это сработает.Я не понимал, что «ученик» ссылался на группы, и у вас были «вложенные» запросы. –

0

Что-то вроде этого?

var bestStudent = i.GroupBy(i=>i.Id) 
    .Select(g=> new Student 
    { 
     Id = g.Key, 
     Name = g.First().Name, 
     Marks = g.Average(i=>i.Marks)) 
    }) 
    .OrderByDescending(s => s.Marks) 
    .FirstOrDefault(); 
+0

, что дало бы вам худшее;) –

+0

исправлено! спасибо –

+0

без проблем ... У меня был тот же код в моем первом тесте :) –

Смежные вопросы