加速list.contains

时间:2013-03-05 10:11:42

标签: .net list generics

我们有一个C#库类,它继承自List但由于List.Contains很慢而很慢。我们无法将类更改为继承自Dictionary或HashSet之类的其他类,因为许多客户端代码依赖于此类,并且它太过涉及更改接口。有没有一种简单的方法来加速这种方法而不改变它?有些列表非常大,所以我们不希望在内存中有两个副本。我们也不想覆盖List的每个方法。

public class UniqueList<T> : List<T>, IList<T>
{
    public new void Add(T item)
    {
        if (!this.Contains(item) && item != null)
        {
            base.Add(item);
        }
    }

3 个答案:

答案 0 :(得分:2)

继承List是一个非常糟糕的主意,因为您无法控制客户端代码如何使用您的类

List.Contains是 O(n)操作。 Dictionary.ContainsKey是一个 O(1),所以我认为使用Dictionary是给出的最佳建议,但如果你真的不想使用它,另一种可能性是保持列表排序为获得 O(log n)

public void Add(T item)
{
    int index = BinarySearch(item);
    if (index < 0)
    {
        Insert(~index, item);
    }
}

如果元素已经在列表中,BinarySearch将返回其索引。 如果元素不在列表中,则BinarySearch方法返回一个负数,它是第一个元素的索引的二进制补码,该索引大于我传递给二分搜索方法的元素。

在您的方案中可能无法使用BinarySearch,因为它取决于T可以是什么: http://msdn.microsoft.com/en-us/library/w4e7fxsh.aspx

此方法使用类型T的默认比较器Comparer.Default来确定列表元素的顺序。 Comparer.Default属性检查类型T是否实现IComparable通用接口并使用该实现(如果可用)。如果不是,Comparer.Default检查类型T是否实现IComparable接口。如果类型T没有实现任何一个接口,Comparer.Default会抛出InvalidOperationException。

答案 1 :(得分:2)

简而言之。

因为你继承自List<>,你实际上是搞砸了,因为即使你对Contains方法有影响,你也无法阻止客户端代码将UniqueList传递给接受的方法List<>,这将隐藏您的新包含,并使用现有的包含。

您需要以困难的方式解决此问题,删除List<>上的继承,实现您自己的包含,从列表中重新实现您需要的任何方法(在内部您可以使用private List<>进行存储,并在必要时委托给那个,并修复此更改中断的所有代码。

当你破坏事物的时候,你可以看一下C5集合类,这些类可以促进对接口的开发,帮助你解决这个问题(我知道,在马拴住之后更多关闭谷仓门)< / p>

我知道这不是你要找的答案,但你不会得到你想要的答案(实际上没有办法解决这个问题,你可以试试Castle Interceptors之类的东西,但我不认为他们会在这种情况下工作......但是我不能确定他们不会这样做。

再次,对于无法真正帮助而道歉。

答案 2 :(得分:0)

你可以拥有一个类级别的私有字典并首先检查字典,如果它没有在字典中找到然后转到列表并检查,它只是一个优化它不是纯粹的解决方案,并且还要花费额外的内存< / p>