简体   繁体   English

有没有排序列表<t> class 在 .NET 中? (不是排序列表<k,v> )</k,v></t>

[英]Is there a SortedList<T> class in .NET? (not SortedList<K,V>)

I need to sort some objects according to their contents (in fact according to one of their properties, which is NOT the key and may be duplicated between different objects).我需要根据它们的内容对一些对象进行排序(实际上是根据它们的一个属性,这不是关键,可能会在不同的对象之间重复)。

.NET provides two classes ( SortedDictionary and SortedList ), and both are implemented using a binary tree. .NET 提供了两个类( SortedDictionarySortedList ),它们都是使用二叉树实现的。 The only differences between them are它们之间唯一的区别是

  • SortedList uses less memory than SortedDictionary. SortedList 使用的 memory 比 SortedDictionary 少。
  • SortedDictionary has faster insertion and removal operations for unsorted data, O(log n) as opposed to O(n) for SortedList. SortedDictionary 对于未排序的数据具有更快的插入和删除操作,O(log n) 而 SortedList 的 O(n)。
  • If the list is populated all at once from sorted data, SortedList is faster than SortedDictionary.如果列表由排序后的数据一次性填充,则 SortedList 比 SortedDictionary 更快。

I could achieve what I want using a List, and then using its Sort() method with a custom implementation of IComparer , but it would not be time-efficient as I would sort the whole List each time I want to insert a new object, whereas a good SortedList would just insert the item at the right position.我可以使用List 实现我想要的,然后将其Sort()方法与IComparer的自定义实现一起使用,但这不会节省时间,因为每次我想插入一个新的 object 时我都会对整个 List 进行排序,而好的 SortedList 只会将项目插入右侧 position。

What I need is a SortedList class with a RefreshPosition(int index) to move only the changed (or inserted) object rather than resorting the whole list each time an object inside changes.我需要的是一个带有 RefreshPosition(int index) 的 SortedList class 以仅移动更改的(或插入的)object,而不是每次 object 内部更改时都重新使用整个列表。

Am I missing something obvious?我错过了一些明显的东西吗?

Maybe I'm slow, but isn't this the easiest implementation ever? 也许我是缓慢的,但不是简单的实现过?

class SortedList<T> : List<T>
{
    public new void Add(T item)
    {
        Insert(~BinarySearch(item), item);
    }
}

http://msdn.microsoft.com/en-us/library/w4e7fxsh.aspx http://msdn.microsoft.com/en-us/library/w4e7fxsh.aspx


Unfortunately, Add wasn't overrideable so I had to new it which isn't so nice when you have List<T> list = new SortedList<T>; 不幸的是, Add了不能覆写,所以我不得不new它,当你有这不是很好List<T> list = new SortedList<T>; which I actually needed to do.... so I went ahead and rebuilt the whole thing... 我实际上需要做的......所以我继续重建整个事情......

class SortedList<T> : IList<T>
{
    private List<T> list = new List<T>();

    public int IndexOf(T item)
    {
        var index = list.BinarySearch(item);
        return index < 0 ? -1 : index;
    }

    public void Insert(int index, T item)
    {
        throw new NotImplementedException("Cannot insert at index; must preserve order.");
    }

    public void RemoveAt(int index)
    {
        list.RemoveAt(index);
    }

    public T this[int index]
    {
        get
        {
            return list[index];
        }
        set
        {
            list.RemoveAt(index);
            this.Add(value);
        }
    }

    public void Add(T item)
    {
        list.Insert(~list.BinarySearch(item), item);
    }

    public void Clear()
    {
        list.Clear();
    }

    public bool Contains(T item)
    {
        return list.BinarySearch(item) >= 0;
    }

    public void CopyTo(T[] array, int arrayIndex)
    {
        list.CopyTo(array, arrayIndex);
    }

    public int Count
    {
        get { return list.Count; }
    }

    public bool IsReadOnly
    {
        get { return false; }
    }

    public bool Remove(T item)
    {
        var index = list.BinarySearch(item);
        if (index < 0) return false;
        list.RemoveAt(index);
        return true;
    }

    public IEnumerator<T> GetEnumerator()
    {
        return list.GetEnumerator();
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return list.GetEnumerator();
    }
}

Or perhaps something like this is a more appropriate Remove function... 或许这样的东西是更合适的Remove功能......

    public bool Remove(T item)
    {
        var index = list.BinarySearch(item);
        if (index < 0) return false;
        while (((IComparable)item).CompareTo((IComparable)list[index]) == 0)
        {
            if (item == list[index])
            {
                list.RemoveAt(index);
                return true;
            }
            index++;
        }
        return false;
    }

Assuming items can compare equal but not be equal... 假设项目可以比较相等但不相等......

I asked a similar question a while back, and there's some good answers there . 我不久前问了一个类似的问题,那里有一些很好的答案 There a good collection of collections here . 有藏品收集好这里

I eventually decided to write it : 我最终决定写它:

class RealSortedList<T> : List<T>
    {
        public IComparer<T> comparer;

        public int SortItem(int index)
        {
            T item = this[index];
            this.RemoveAt(index);
            int goodposition=FindLocation(this[index], 0, this.Count);
            this.Insert(goodposition, item);
            return goodposition;
        }

        public int FindLocation(T item, int begin, int end)
        {
            if (begin==end)
                return begin;
            int middle = begin + end / 2;
            int comparisonvalue = comparer.Compare(item, this[middle]);
            if (comparisonvalue < 0)
                return FindLocation(item,begin, middle);
            else if (comparisonvalue > 0)
                return FindLocation(item,middle, end);
            else
                return middle;
        }
    }

Don't forget that inserting an item into a list backed by an array can be an expensive operation - inserting a bunch of items and then sorting may well be quicker unless you really need to sort after every single operation. 不要忘记将项目插入由数组支持的列表中可能是一项昂贵的操作 - 插入一堆项目然后排序可能会更快,除非您确实需要在每次操作后进行排序。

Alternatively, you could always wrap a list and make your add operation find the right place and insert it there. 或者,您可以始终包装列表并使添加操作找到正确的位置并将其插入其中。

I've solved this problem in the past by writing an extension method that does a binary search on a IList, and another that does an insert. 我过去通过编写一个在IList上进行二进制搜索的扩展方法和另一个执行插入的方法解决了这个问题。 You can look up the correct implementation in the CLR source because there's a built-in version that works only on arrays, and then just tweak it to be an extension on IList. 您可以在CLR源中查找正确的实现,因为有一个仅适用于数组的内置版本,然后只需将其调整为IList上的扩展。

One of those "should be in the BCL already" things. 其中一个“应该在BCL已经”的事情。

What I need is a SortedList class with a RefreshPosition(int index) to move only the changed (or inserted) object rather than resorting the whole list each time an object inside changes. 我需要的是一个带有RefreshPosition(int索引)的SortedList类,它只移动已更改(或插入)的对象,而不是每次内部对象更改时都使用整个列表。

Why would you update using an index when such updates invalidate the index? 当此类更新使索引无效时,为什么要使用索引进行更新? Really, I would think that updating by object reference would be more convenient. 真的,我认为通过对象引用更新会更方便。 You can do this with the SortedList - just remember that your Key type is the same as the return type of the function that extracts the comparable data form the object. 您可以使用SortedList执行此操作 - 只需记住您的Key类型与从对象中提取可比较数据的函数的返回类型相同。

class UpdateableSortedList<K,V> {
    private SortedList<K,V> list = new SortedList<K,V>();
    public delegate K ExtractKeyFunc(V v);
    private ExtractKeyFunc func;

    public UpdateableSortedList(ExtractKeyFunc f) { func = f; }

    public void Add(V v) {
        list[func(v)] = v;
    }
    public void Update(V v) {
        int i = list.IndexOfValue(v);
        if (i >= 0) {
            list.RemoveAt(i);
        }
        list[func(v)] = v;
    }
    public IEnumerable<T> Values { get { return list.Values; } }
}

Something like that I guess. 我想是这样的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM