C#/ .NET比较两个大列表并从两个列表中查找缺失的项

时间:2019-03-13 13:21:53

标签: c# linq

所以基本上我有两个大列表,如下所示:

public class Items
{
 public string ItemID { get; set; }
}


var oldList = new List<Items>(); // oldList

var newList = new List<Items>(); // new list

两个列表都非常大,并且如果两个列表都很大(超过30秒),则由于执行时间较差,因此简单的double foreach就不够了。

在我对stackoverflow提出的上一个问题中,我得到了一个答复,该答复是如何比较这两个相同的列表并找出哪些项目具有不同的QuantitySold参数,然后将其存储在名为“ DifferentQuantityItems”的第三个列表中,如下所示:

var differentQuantityItems =
    (from newItem in newList
     join oldItem in oldList on newItem.ItemID equals oldItem.ItemID
     where newItem.QuantitySold != oldItem.QuantitySold
     select newItem).ToList();

现在我想从这两个列表中获得以下信息:

- A list of items that are present in newList, but not in oldList

- A list of items that are present in oldList, but not in newList

我该如何实现?有人可以帮我吗?

P.S。我会通过属性“ ItemID”“知道”列表中的任何一项都不存在的方式……

5 个答案:

答案 0 :(得分:2)

您是否考虑过将列表转换为哈希集并使用Except方法?

请参见Difference between two lists

并且:Is there a way to get the difference between two sets of objects in c#

答案 1 :(得分:1)

var items = new List<int>(oldList.Select(x => x.ItemID ));
var missingValues = newList.Where(x => !diffids.Contains(x.ItemID)).ToList();

您还可以使用除外。

答案 2 :(得分:1)

已编辑

除了可以更快地工作。 Here您可以读到它的性能

var missedOld = oldList.Except(newList, new ItemsEqualityComparer());
var oldList= oldList.Except(missedOld, new ItemsEqualityComparer());

旧答案

两个缺少项目的列表

var missedOld = oldList.Where(x => !newList.Select(i => i.ItemID).Contains(x.ItemID)) 
var missedNew = newList.Where(x => !oldList.Select(i => i.ItemID).Contains(x.ItemID))

一个列表中所有错过的物品:

oldList.Concat(newList).GroupBy(x => x.ItemID).Where(x => x.Count() < 2).Select(x => x.Value).ToList()

答案 3 :(得分:0)

如果列表足够大,以至于嵌套循环需要30秒钟,我建议您将每个列表的项放入各自的HashSet中,并使用该项查找异常。哈希表的缩放比例为O(1)或O(log N),而比较2个未排序的列表为O(n ^ 2)。

话虽如此,请尝试使用Linq Except()

var notinNewList = oldList.Except(newList);

如果我没记错的话,.Except()的内部实现依赖于HashSets

第二,如果列表已排序,或者可以进行预排序,则可以一口气进行线性传递而无需嵌套循环,这可能比任何方法都要快。

我不建议使用List.Contains(),因为它是一个线性实现,这将导致您尝试避免相同的O(n ^ 2),尽管由于Linq语法的原因,它看起来更漂亮糖。

答案 4 :(得分:-1)

var items = newList.Where(n => !oldlist.Any(o => o.ItemID == n.ItemID)).ToList();

它更加灵活,因为您无需再次进入DB且无需使用Contains(就像在SQL中一样,它也位于一行中。)