Simplest way to filter value from generic List in

2020-02-10 12:53发布

I have two classes. The first one is Person, and the second one is Student (which inherits from Person). I want to filter a generic List and find all Students which grades are higher than 7. I came up with the following solution:

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;
        });
    }
}

Is there a simpler way to filter this list?

标签: c# linq
3条回答
▲ chillily
2楼-- · 2020-02-10 13:20

Here's a few different ways of doing it, with some relative performance numbers:

Initial

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

Initial Modified (same speed as Initial)

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

OfType (40-52% SLOWER than Initial)

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

Foreach (9-16% faster than Initial)

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

For (12-18% faster than initial)

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);
    }
}

To get the performance numbers, I:

  • Ran a control test that did nothing
  • Timed each of the functions 100 times over a List with 10 to 1,000,000 elements
  • Subtracted the control time from each tests time (to make the results more accurate)
  • Each function used the same random data set and ToList was used to force the enumerator to run

Of course, these are just performance numbers on my machine, you'll have to test on real-world data to get actual results as the distribution of Students vs. People, the average grade of the student, etc. will cause a lot of variation in the timings.

查看更多
ら.Afraid
3楼-- · 2020-02-10 13:31

The only improvement I see is using OfType, like this

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

...and my syntax is simpler... but that is in the eye of the beholder.

查看更多
你好瞎i
4楼-- · 2020-02-10 13:37
people.RemoveAll(p => p.Grade <= 7);
查看更多
登录 后发表回答