添加到列表之前的检查和linq中的区别之间存在性能



在foreach循环中,我想将产品添加到列表中,但我希望此列表不包含重复的产品,目前我已经解决了两个想法。

1/在循环中,在将产品添加到列表之前,我会检查该产品是否已经存在于列表中,否则我会将其添加到列表中。

foreach (var product in products)
{
// code logic
if(!listProduct.Any(x => x.Id == product.Id))
{
listProduct.Add(product);
}
}

2/。在循环中,即使有重复的产品,我也会将所有产品添加到列表中。然后在循环之外,我将使用Distinct来删除重复的记录。

foreach (var product in products)
{
// code logic
listProduct.Add(product);
}
listProduct  = listProduct.Distinct().ToList();

我想知道这两种方式是最有效的。或者有其他想法可以将记录添加到列表中以避免重复??

我会选择第三种方法:哈希集它有一个接受IEnumerable的构造函数重载。此构造函数删除重复项:

如果输入集合包含重复项,则集合将包含一个每个独特元素。不会引发任何异常。

来源:HashSet<T>Constructor

用法:

List<Product> myProducts = ...;
var setOfProducts = new HashSet<Product>(myProducts);

去除重复后,setOfProducts[4]就没有了正确的含义。

因此,HashSet不是IList<Product>,而是ICollection<Product>,您可以使用List进行计数/添加/删除等操作。你唯一不能做的就是通过索引获取

您首先要了解哪些元素不在集合中:

var newProducts = products.Where(x => !listProduct.Any(y => x.Id == y.Id));

然后使用AddRang 添加它们

listProduct.AddRagne(newItems)

或者你也可以使用foreach循环太

foreach (var product in newProducts)
{
listProduct.Add(product);
}

1更简单的解决方案是无需使用Distint

var newProductList = products.Union(listProduct).ToList();

但工会的表现并不好。

根据所包含的内容,您将所有内容都存储在内存中。如果是这种情况,或者只有在准备好之后才进行持久化,则可以考虑使用BinarySearch:https://msdn.microsoft.com/en-us/library/w4e7fxsh(v=vs.110(.aspx,最后还会得到一个有序列表。如果排序不重要,您可以使用HashSet,它非常快速,并且专门用于此目的。

同时检查:https://www.dotnetperls.com/hashset

这应该很快,可以处理任何订单:

// build a HashSet of your primary keys type (I'm assuming integers here) containing all your list elements' keys
var hashSet = new HashSet<int>(listProduct.Select(p => p.Id));
// add all items from the products list whose Id can be added to the hashSet (so it's not a duplicate)
listProduct.AddRange(products.Where(p => hashSet.Add(p.Id)));

不过,您可能需要考虑的是在Product类型上实现IEquatable<Product>并重写GetHashCode(),这将使上面的代码更容易,并将相等性检查放在它们应该在的位置(在相应的类型内(:

var hashSet = new HashSet<int>(listProduct);
listProduct.AddRange(products.Where(hashSet.Add));

最新更新