在C#中有效地消除比较两个大列表的重复

本文关键字:两个 列表 有效地 比较 | 更新日期: 2023-09-27 18:29:55

我有两个大列表,list1有4列,list2有3列。如果list1在第1列和第3列中包含与list2相同的值,那么我需要删除list1中的该项。实际上,我正在寻找一些优势和有效的解决方案。谢谢你的帮助。

List1:
1, 5, 3, 9     // Remove this
11, 15, 18, 6  // Keep this  
List2:
1, 5, 3
List<Tuple<int, int, int, int>> list1 = new List<Tuple<int, int, int, int>>();
List<Tuple<int, int, int>> list2 = new List<Tuple<int, int, int>>();

在C#中有效地消除比较两个大列表的重复

从性能的角度来看,理想情况下您可以利用HashSet.SymmetricExceptWith,但您使用的是两种不同的类型(和Tuples)。

Except是一种可能的解决方案:

list1 = list1.Except(list1
    .Where(l1 => list2
        .Any(l2 => l2.Item1 == l1.Item1
            && l2.Item2 == l1.Item2
            && l2.Item3 == l1.Item3)))
    .ToList();
        var index2 = list2.ToLookup(t => Tuple.Create(t.Item1, t.Item3));
        //var index2 = list2.Select(l => Tuple.Create(l.Item1, l.Item3)).ToList();
        //index2.Sort();
        var results = from l in list1
                      where !index2.Contains(Tuple.Create(l.Item1, l.Item3))
                      select l;

这可能相当有效。不利的一面是index2使用了额外的内存。注释掉了另一种索引方法,这种方法在内存上会更容易一些。ToList版本不会存储对原始记录的引用,因此它将更加轻量级。但是ToLookup索引可能比这个特定的问题对你有更多的用处。如果每个键都是唯一的,ToDictionary也将是一个选项,而不是ToLookup,但这是向重量级的后退了一步。

根据这些列表的实际大小,通过几个位置良好的AsParallel()调用可能会获得额外的收益。

        var index2 = list2.AsParallel().ToLookup(t => Tuple.Create(t.Item1, t.Item3));
        var results = from l in list1.AsParallel()
                      where !index2.Contains(Tuple.Create(l.Item1, l.Item3))
                      select l;

用其中一种或另一种或两者进行实验,因为只有你的环境才能告诉我们这是否是最好的。有时,在多个线程上拆分工作所花费的时间可能比串行完成工作花费的时间更长。