排除列表

时间:2017-05-17 10:27:07

标签: c# linq

我正在寻找最优雅和有效的方法来排除另一个列表中存在的元素。让我们说:

List<A> As which contains more than 1 000 000 records
List<B> Bs which contains more than 100 000 records

我需要删除As等于As.Id的列表Bs.Id中的所有元素。我只需要从包含相同Id的Bs中减少As的元素。操作我重复数百次。解决该问题的最有效(和优雅)方法是什么?我希望 LINQ NotIn

foreach(a in As)
{
    if(Bs.Any(b => b.Id == a.Id)
        As.Remove(a);
}

需要很长时间才能完成。

3 个答案:

答案 0 :(得分:5)

假设A.Id以及B.Id的类型为int,您可以将List<B>转换为HashSet<int>效率 )而不是使用RemoveAll(它应该是优雅?):

//TODO: I've assumed that Id is of type int, change HashSet<T> if required 
// Efficiency: HashSet.Contains has O(1) time complexity when List.Contains - O(n)
HashSet<int> IdsToExclude = new HashSet<int>(Bs
  .Select(b => b.Id)); // <- Linq (Select) is OK here...

// ... but not here (efficiency and if you don't mind, elegancy):
// We don't want Linq since Linq (Except) will create a new collection of about 1e6 items
// All we want is to modify the existing collection in place: RemoveAll
As.RemoveAll(a => IdsToExclude.Contains(a.Id));

答案 1 :(得分:0)

你原来的方法太慢了,因为它是O(n ^ 3)。 如果你必须使用try-catch(不友好删除)并且其中有很多项目,在这种情况下我认为过滤然后重新分配列表而不是就地过滤可能更好因为ListRemove内部必须首先过滤然后部分清除支持数组以删除元素。

如果RemoveAll包含唯一的ID,那么将其转换为字典(或者更好地从字典开始)可能比过滤列表更有效。

As

答案 2 :(得分:0)

如果两个类都是从具有id属性的基类继承的:

class Entity
{
    public int Id { get; set; }
}
class A : Entity
{
    public string SomeProp { get; set; }
}
class B : Entity
{
    public string OtherProp { get; set; }
}

你可以创建比较器:

class EntityComparer : IEqualityComparer<Entity>
{
    public bool Equals(Entity x, Entity y) => x.Id.Equals(y.Id);
    public int GetHashCode(Entity obj) => base.GetHashCode();
}

并使用Except方法:

first.Except(second, new EntityComparer()).OfType<A>();

否则使用Dmitry Bychenko方法https://stackoverflow.com/a/44022567/6503504