如何使用LINQ从两个列表中有效地选择某些项目

时间:2013-01-28 22:18:32

标签: c# linq

我有这三个班级:

  • 员工
  • 学生

public class Employee
{
    public Guid Id { get; set; }
    public string Name { get; set; }
    public int Age { get; set; }
    public string Gender { get; set; }
    public long TimeStamp { get; set; }
 }

public class Student
{
      public Guid Id { get; set; }
      public string Name { get; set; }
      public int Age { get; set; }
      public long TimeStamp { get; set; }
}

public class Person<br>
{
    public string Name { get; set; }
    public int Age { get; set; }
}

public class Employee { public Guid Id { get; set; } public string Name { get; set; } public int Age { get; set; } public string Gender { get; set; } public long TimeStamp { get; set; } } public class Student { public Guid Id { get; set; } public string Name { get; set; } public int Age { get; set; } public long TimeStamp { get; set; } } public class Person<br> { public string Name { get; set; } public int Age { get; set; } }

我创建了4个列表:

//选择所有学生和员工

var studentList = new List<Student>();// fill the List with a lot of Stundents
var employeeList = new List<Student>(); // fill the List with a lot of employees
var personList1 = new List<Person>();
var personList2 = new List<Person>();

//我想将所有学生映射到

var allStudents = studentList.Select(a => a); // does not make a lot of sence but for testing 
var allEmployee = employeeList.Select(b => b);

//我想让allStundent列表中没有提到TimeStape值的所有Employees

personList1.AddRange(allStudents.Select(a => new Person()
            {
               Age = a.Age,
               Name = a.Name
            } ));

//再次映射

var allEmployeesWithDifferentTimeStampThanStundent =
    allEmployee.Where(a => !allStudents.Select(b =>b.TimeStamp).Contains(a.TimeStamp));

//合并两个列表

personList2.AddRange(allEmployeesWithDifferentTimeStampThanStundent.Select
(a => new Person()
    {
    Age = a.Age,
    Name = a.Name
    } ));

有更好更有效的方法吗?

2 个答案:

答案 0 :(得分:4)

personList2变量仅作为投影到Person类型的中间体出现 - 如果是这种情况,您可以跳过其创建并使用如下查询语法:

var personsFromNonMatchingEmployees =
    from employee in allEmployee
    join student in allStudents
    on employee.TimeStamp equals student.TimeStamp into studentsWithMatchingTimeStamp
    where !studentsWithMatchingTimeStamp.Any()
    select new Person { Age = employee.Age, Name = employee.Name };

personList1.AddRange(personsFromNonMatchingEmployees);

这类似于其他GroupJoin方法,因为编译器将上述内容转换为GroupJoin调用。 join / group-join的使用必然比Where..Contains方法表现得更好,因为它使用了散列 - 换句话说,它是一个算法Big-O改进,对于任何超过几个学生或者应该是非常明显的员工实例。

通过在查询中选择new Person对象,我可以完全绕过personList2列表。我发现我几乎总是能够通过做这样的选择来消除临时列表,这些选择投射到我真正感兴趣的类型。我也遗漏了()上的new Person { .. },因为编译器不需要它。

羞于改变继承并使员工:人与人学生:伙计,我认为还有很多需要改进的地方。

答案 1 :(得分:2)

您可以使用GroupJoin查找所有没有匹配Student记录且具有相同时间戳的员工:

var employeesDiffTS = allEmployee
    .GroupJoin(allStudents, e => e.TimeStamp, s => s.TimeStamp, (e, students) => new { Emp = e, HasMatch = students.Any() })
    .Where(em => !em.HasMatch)
    .Select(em => em.Emp)

personList2.AddRange(employeeDiffTS.Select(a => new Person { Age = a.Age, Name = a.Name }));

personList1.AddRange(personList2);