Самый простой способ фильтрации значения из общего списка в С# с использованием LINQ

У меня есть два класса. Первый - это Person, а второй - Student (который наследуется от Person). Я хочу отфильтровать общий список и найти все Студенты, которые имеют выше 7. Я придумал следующее решение:

class Person
{
    public string Name {get; set;}
}

class Student : Person
{
    public decimal Grade {get; set;}
}

class Program
{
    static void Main(string[] args)
    {
        List<Person> people = new List<Person>();
        people.Add(new Person() {Name="John"});
        people.Add(new Student() {Name="Joe", Grade=6});
        people.Add(new Student() {Name="Jane", Grade=8});

        people.Where(delegate (Person person) {
            var student = person as Student;
            return student != null && student.Grade > 7;
        });
    }
}

Есть ли более простой способ фильтрации этого списка?

Ответы

Ответ 1

Единственное улучшение, которое я вижу, это использовать OfType, как этот

var result = people.OfType<Student>().Where(s => s.Grade > 7);

... и мой синтаксис проще... но это в глазах смотрящего.

Ответ 2

Вот несколько разных способов сделать это, с некоторыми относительными номерами производительности:

Начальное

people.Where(delegate(Person person)
{
    var student = person as Student;
    return student != null && student.Grade > 7m;
});

Начальное изменение (с той же скоростью, что и начальная)

people.Where(p =>
{
    var student = p as Student;
    return student != null && student.Grade > 7m;
});

OfType (40-52% SLOWER, чем начальное)

people.OfType<Student>().Where(s => s.Grade > 7m)

Foreach (На 9-16% быстрее Начального)

var results = new List<Student>();
foreach (var person in people)
{
    var student = person as Student;
    if (student != null && student.Grade > 7m)
    {
         results.Add(student);
    }
}

Для (На 12-18% быстрее первоначального)

var results = new List<Student>();
for (var idxPerson = 0; idxPerson < people.Count; idxPerson++)
{
    var student = people[idxPerson] as Student;
    if (student != null && student.Grade > 7m)
    {
        results.Add(student);
    }
}

Чтобы получить номера производительности, I:

  • Выполните контрольный тест, который ничего не сделал
  • Запланировала каждую из функций 100 раз над списком с 10 до 1 000 000 элементов.
  • Вычитает время управления из каждого времени тестирования (чтобы сделать результаты более точными)
  • Каждая функция использовала один и тот же набор случайных данных и ToList, чтобы заставить счетчик запускать

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

Ответ 3

people.RemoveAll(p => p.Grade <= 7);