如何在C#中有效地比较两个排序的大型列表?

时间:2012-01-09 22:14:40

标签: c# .net

我有两个通用列表,每个列表中包含20,000和30,000个对象。

class Employee
{
    string name;
    double salary;
}

List<Employee> newEmployeeList = List<Employee>() {....} // contains 20,000 objects
List<Employee> oldEmployeeList = List<Employee>() {....} // contains 30,000 objects

如果列表提高了速度,也可以按名称对列表进行排序。

我想比较这两个列表以找出

  1. 姓名和薪资匹配的员工
  2. 名称匹配但不是薪水的员工
  3. 将这些大型数据列表与上述条件进行比较的最快方法是什么?

5 个答案:

答案 0 :(得分:2)

我会按newEmployeeList - oldEmployeeListnameO(n*log(n))个列表进行排序。然后你可以使用线性算法来搜索匹配。因此,如果两个列表的大小相同,则总计为O(n+n*log(n))。这应该比O(n^2)“强力”算法快。

答案 1 :(得分:2)

我可能会建议根据名称开始将两个列表存储在Dictionary<string, Employee>中,然后您可以在一个中迭代键并查找它们是否存在且工资是否匹配其他。这也可以节省以后对它们进行排序或将它们放在更有效的结构中的成本。

这几乎是O(n) - 线性构建两个字典,线性通过键和查找另一个。由于O(n + m + n)减少到O(n)

但是,如果由于其他原因必须使用List<T>来保存列表,您还可以使用Join() LINQ方法,并使用{构建一个新列表{1}}字段,告诉您它们是匹配还是不匹配...

Match

然后,您可以使用 var results = newEmpList.Join( oldEmpList, n => n.Name, o => o.Name, (n, o) => new { Name = n.Name, Salary = n.Salary, Match = o.Salary == n.Salary }); Where()的{​​{1}}子句对其进行过滤。

答案 2 :(得分:2)

更新:我假设(根据您的问题标题)2个列表已经排序。也许它们存储在具有聚簇索引的数据库中。因此,这个答案依赖于这个假设。

这是一个具有O(n)复杂度的实现,也非常快,而且非常简单 我相信这是Merge Algorithm的变体。

以下是这个想法:

  1. 开始枚举两个列表
  2. 比较2个当前项目。
  3. 如果匹配,请添加到您的搜索结果中 如果第一项是“较小”,则前进第一个列表 如果第二项是“较小”,则前进第二个列表。
  4. 由于已知两个列表都已排序,因此这将非常有效。此实现假定name在每个列表中都是唯一的。

    var comparer = StringComparer.OrdinalIgnoreCase;
    var namesAndSalaries = new List<Tuple<Employee, Employee>>();
    var namesOnly = new List<Tuple<Employee, Employee>>();
    
    // Create 2 iterators; one for old, one for new:
    using (IEnumerator<Employee> A = oldEmployeeList.GetEnumerator()) {
        using (IEnumerator<Employee> B = newEmployeeList.GetEnumerator()) {
            // Start enumerating both:
            if (A.MoveNext() && B.MoveNext()) {
                while (true) {
                    int compared = comparer.Compare(A.Current.name, B.Current.name);
                    if (compared == 0) {
                        // Names match
                        if (A.Current.salary == B.Current.salary) {
                            namesAndSalaries.Add(Tuple.Create(A.Current, B.Current));
                        } else {
                            namesOnly.Add(Tuple.Create(A.Current, B.Current));
                        }
                        if (!A.MoveNext() || !B.MoveNext()) break;
                    } else if (compared == -1) {
                        // Keep searching A
                        if (!A.MoveNext()) break;
                    } else {
                        // Keep searching B
                        if (!B.MoveNext()) break;
                    }
    
                }
            }
        }
    }
    

答案 3 :(得分:1)

您可以使用

创建词典
var lookupDictionary = list1.ToDictionary(x=>x.name);

如果您从一个循环中查找另一个列表中的值,那么这将使您接近O(1)查找并接近O(n)行为。

(我在这里假设ToDictionary是O(n),这对于直接实现是有意义的,但我没有测试过这种情况)

这会产生一个非常直接的算法,而且我认为在O(n)之下使用两个未排序的列表非常困难。

答案 4 :(得分:0)

已排序列表中一个最快的解决方案是使用BinarySearch来查找其他列表中的项目。

但是,在提到其他人时,您应该根据您的项目要求来衡量它,因为性能通常往往是主观事物。