'Finding the biggest TestId in the list

I want to find the biggest TestId for each Student. I am using the following code which I hope has no bug. Notice that the list size may be any number but each TestId for each Student is a unique number (A student can not have two the same TestId means each student can just contribute one time i each test).

In the following code, actually I first ordered the list by the studentId then by the TestId, then I compare each StudentId with the next one. If the the current and the next studentId are not the same, the current Studet TestId will have the biggest one. In this kind of comparing the first and the last should be chosen in another way. So I used an if statement to do it (hope is correct).

It works but I think there is another clean solution to do it. If someone knows please help.

static void Main()
    {
        IList<Info> InfoList = new List<Info>{
                    new Info{ StudentId = 1 , TestId = 1 , Point = 10 },
                    new Info{ StudentId = 1 , TestId = 2 , Point = 5 },
                    new Info{ StudentId = 1 , TestId = 3 , Point = 5 },
                    new Info{ StudentId = 2 , TestId = 1 , Point = 6 },
                    new Info{ StudentId = 1 , TestId = 3 , Point = 4 },
                    new Info{ StudentId = 3 , TestId = 1 , Point = 6 },
                    new Info{ StudentId = 4 , TestId = 1 , Point = 9 },
                    new Info{ StudentId = 1 , TestId = 4 , Point = 5 },
                    new Info{ StudentId = 5 , TestId = 2 , Point = 10 },
                    new Info{ StudentId = 2 , TestId = 2 , Point = 8 },
                    new Info{ StudentId = 6 , TestId = 1 , Point = 5 },
                    new Info{ StudentId = 8 , TestId = 1 , Point = 7 }
        }.OrderBy(i => i.StudentId).ThenBy(i => i.TestId).ToList();


        int infoNumber = InfoList.Count;

        IList<Info> InfoList2 = new List<Info>();

        //I am using the followig for loop to find the Biggest TestId for each student.
        for (int i = 0; i < infoNumber; i++)
        {
            if (i + 1 == infoNumber)
            {
                if (InfoList[0].StudentId == InfoList[infoNumber-1].StudentId )
                {
                    InfoList2.Add(InfoList[i]);
                }
                else
                {
                    if ((InfoList[i].StudentId != InfoList[i - 1].StudentId))
                    {
                        InfoList2.Add(InfoList[i]);
                    }
                }
                break;
            }
            if ((InfoList[i].StudentId != InfoList[i + 1].StudentId))
            {
                InfoList2.Add(InfoList[i]);
            }
        }
        //Result
        foreach (var item in InfoList2)
        {
            Console.WriteLine($"StudentId: {item.StudentId}, TestId: {item.TestId}, Point: {item.Point}");
        }
    }
}

public class Info
{
    public int StudentId { get; set; }
    public int TestId { get; set; }
    public double Point { get; set; }
}


Solution 1:[1]

Using .Net 6.0 Enumerable.MaxBy, you can remove the OrderBy and just do:

var InfoList2 = InfoList.GroupBy(st => st.StudentId)
                        .Select(stg => stg.MaxBy(st => st.TestId));

If you are on earlier .Net, you can define it yourself with:

public static EnumerableExt {
    public static T MaxBy<T, TKey>(this IEnumerable<T> items, Func<T, TKey> keyFn, Comparer<TKey> keyComparer) => items.Aggregate((a, b) => keyComparer.Compare(keyFn(a), keyFn(b)) >= 0 ? a : b);
    public static T MaxBy<T, TKey>(this IEnumerable<T> items, Func<T, TKey> keyFn) => items.Aggregate((a, b) => Comparer<TKey>.Default.Compare(keyFn(a), keyFn(b)) >= 0 ? a : b);
    public static T MinBy<T, TKey>(this IEnumerable<T> items, Func<T, TKey> keyFn, Comparer<TKey> keyComparer) => items.Aggregate((a, b) => keyComparer.Compare(keyFn(a), keyFn(b)) <= 0 ? a : b);
    public static T MinBy<T, TKey>(this IEnumerable<T> items, Func<T, TKey> keyFn) => items.Aggregate((a, b) => Comparer<TKey>.Default.Compare(keyFn(a), keyFn(b)) <= 0 ? a : b);
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 NetMage