查找其他列表中不存在的所有项目需要花费大量时间

本文关键字:时间 项目 列表 其他 不存在 查找 | 更新日期: 2023-09-27 18:26:26

我有两个通用列表,一个有70000多个项目,另一个有10个项目。当与第一个列表进行比较时,我必须找出第二个列表中不存在的项目。从逻辑上讲,我的代码运行良好,使用较小的列表集不会遇到任何严重的性能问题。由于我的第一个清单是超过70000个项目,我面临着严重的性能问题。执行和获得结果需要花费大量时间。

我的问题是?有更好的方法吗?我无法忍受这个性能问题。有什么改进的建议吗?我正在使用C#,.NET 3.5

List<Employee> existingEmployeeList = List of 70K employees;
List<Employee> validEmployeeList = List of 10 employees;
var emloyeeDeletedFilterList = existingEmployeeList.Where(m => !validEmployeeList.Any(p => p.EmployeeId == m.EmployeeId
                            && p.FirstName == m.FirstName
                            && p.Age == m.Age
                            && p.LastName == m.LastName));

我还有其他操作要查找,这些操作是新添加到列表中的。

var emloyeeAddedFilterList = validEmployeeList.Where(m => !existingEmployeeList.Any(p => p.EmployeeId == m.EmployeeId
                                && p.FirstName == m.FirstName
                                && p.Age == m.Age
                                && p.LastName == m.LastName));

我在where子句中有4个条件来筛选员工列表。

编辑了我的问题:又添加了一个代码片段

查找其他列表中不存在的所有项目需要花费大量时间

编写一个自定义EqualityComparer<Employee>来比较您的4个字段,然后使用.Intersect(进行

var emloyeeFilterList = validEmployeeList.Intersect(existingEmployeeList, new EmployeeComparer()).ToList();

我认为在validEmployeeList而不是existingEmployeeList上调用.Intersect(会更快,但我会通过两种方式进行测试以确定。

更新:

哎呀,误解了你想要什么。您想要使用的查询是Except,而不是Intersect

如果您想要除有效员工以外的所有现有员工

var emloyeeFilterList = existingEmployeeList.Execpt(validEmployeeList, new EmployeeComparer()).ToList();

或者如果您想要除现有员工之外的所有有效员工。

var emloyeeFilterList = validEmployeeList.Execpt(existingEmployeeList, new EmployeeComparer()).ToList();

这里还有一个如何编写EmployeeComparer 的示例

public class EmployeeComparer : EqualityComparer<Employee>
{
    public override bool Equals(Employee x, Employee y)
    {
         return x.EmployeeId == y.EmployeeId
             && x.FirstName == y.FirstName
             && x.Age == y.Age
             && x.LastName == y.LastName
    }
    //Implmentation taken from http://stackoverflow.com/questions/263400/what-is-the-best-algorithm-for-an-overridden-system-object-gethashcode
    public override int GetHashCode(Employee obj)
    {
        unchecked // Overflow is fine, just wrap
        {
            int hash = (int) 2166136261;
            // Suitable nullity checks etc, of course :)
            hash = hash * 16777619 ^ obj.EmployeeId.GetHashCode();
            hash = hash * 16777619 ^ obj.FirstName.GetHashCode();
            hash = hash * 16777619 ^ obj.Age.GetHashCode();
            hash = hash * 16777619 ^ obj.LastName.GetHashCode();
            return hash;
        }
    }
}

考虑使用HashSet来存储元素。哈希集要求您重载类的哈希函数。

此外,CPU可以比任何其他类型更快地比较整数。在遍历元素时,请考虑实现更多的整数比较。

如果你对衡量性能感兴趣,请阅读关于评估程序相对性能的大O方法论。

节日快乐

对于我可以从您的代码示例中解释的内容,您似乎只需要检查"EmployeeId"。如果不是这样,您可以尝试以下操作来避免使用LinQ,因为它没有显式迭代那么快。

List<Employee> employeeFilterList = new List<Employee>();
for(int a = validEmployeeList.Count; --a >= 0; )
{
    for(int b = existingFieldMappingList.Count; --b >= 0; )
    {
        Employee aEmployee = validEmployeeList[a];
        Employee bEmployee = validEmployeeList[b];
        if (aEmployee.EmployeeId != bEmployee.EmployeeId)
            continue;
        if (aEmployee.FirstName != bEmployee.FirstName)
            continue;
        if (aEmployee.Age != bEmployee.Age)
            continue;
        if (aEmployee.LastName != bEmployee.LastName)
            continue;
        employeeFilterList.Add(aEmployee);
    }
}

编辑:请记住,您可以按照第一个条件最有可能跳到下一次迭代的方式重新排序IF条件。