Подтвердить что ты не робот

Есть класс SortedList <T> в .NET?

Мне нужно отсортировать некоторые объекты в соответствии с их содержимым (фактически в соответствии с одним из их свойств, которое НЕ является ключом и может быть дублировано между разными объектами).

.NET предоставляет два класса (SortedDictionary и SortedList), и оба они реализованы с использованием двоичного дерева. Единственные различия между ними:

  • SortedList использует меньше памяти, чем SortedDictionary.
  • SortedDictionary имеет более быстрые операции вставки и удаления для несортированных данных, O (log n), в отличие от O (n) для SortedList.
  • Если список заполняется сразу из отсортированных данных, SortedList работает быстрее, чем SortedDictionary.

Я мог бы достичь того, что хочу, используя List,, а затем используя Sort() с пользовательской реализацией IComparer, но это было бы неэффективно, поскольку я бы сортировал весь список каждый раз, когда я хочу вставить новый объект, тогда как хороший SortedList просто вставляет элемент в нужное положение.

Мне нужен класс SortedList с RefreshPosition (int index), чтобы перемещать только измененный (или вставленный) объект, а не прибегать к списку всего при каждом изменении объекта внутри.

Я пропустил что-то очевидное?

4b9b3361

Ответ 1

Возможно, я медленный, но разве это не самая простая реализация?

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

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


К сожалению, Add не был переопределяемым, поэтому я должен был new, что не так приятно, когда у вас есть List<T> list = new SortedList<T>;, который мне действительно нужно делать.... поэтому я пошел вперед и перестроил весь вещь...

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();
    }
}

Или возможно что-то вроде более подходящей функции 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;
    }

Предполагая, что элементы могут сравниваться равными, но не быть равными...

Ответ 2

Я задал подобный вопрос некоторое время назад, и там есть хорошие ответы. Там есть хорошая коллекция коллекций здесь.

Ответ 3

В конце концов я решил написать его:

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;
        }
    }

Ответ 4

Не забывайте, что вставка элемента в список, поддерживаемый массивом, может быть дорогостоящей операцией - вставка кучки элементов, а затем сортировка может быть быстрее, если вам действительно не нужно сортировать после каждой отдельной операции.

Кроме того, вы всегда можете обернуть список и сделать операцию добавления найти нужное место и вставить туда.

Ответ 5

Я решил эту проблему в прошлом, написав метод расширения, который выполняет двоичный поиск в IList, а другой - вставку. Вы можете найти правильную реализацию в источнике CLR, потому что есть встроенная версия, которая работает только на массивах, а затем просто настраивает ее как расширение на IList.

Один из них "должен быть в BCL уже".

Ответ 6

Мне нужен класс SortedList с a RefreshPosition (индекс int) для перемещения только измененный (или вставленный) объект вместо того, чтобы использовать весь список каждый раз, когда изменяется объект внутри.

Почему вы обновляете с помощью index, когда такие обновления недействительны для индекса? Действительно, я думаю, что обновление по ссылке на объект было бы более удобным. Вы можете сделать это с помощью 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; } }
}

Что-то вроде этого, я думаю.