Как мне отсортировать IList ‹Class›?

Для IList нет Sort() функции. Может ли кто-нибудь помочь мне с этим? Я хочу отсортировать свой собственный список IList.

Предположим, это мой IList:

public class MyObject() 
{
 public int number { get; set; }
 public string marker { get; set; }
}

Как отсортировать myobj с помощью строки маркера?

public void SortObject()
{
 IList<MyObject> myobj = new List<MyObject>();
}

person Rye    schedule 02.10.2010    source источник
comment
myobj всегда List? Если это так, вы можете преобразовать его в List и запустить его Sort функцию.   -  person Gabe    schedule 02.10.2010


Ответы (5)


Используйте OrderBy.

Пример

public class MyObject() 
{
    public int number { get; set; }
    public string marker { get; set; }
}

IList<MyObject> myobj = new List<MyObject>();
var orderedList = myobj.OrderBy(x => x.marker).ToList();

Для нечувствительности к регистру вы должны использовать IComparer

public class CaseInsensitiveComparer : IComparer<string>
{
    public int Compare(string x, string y)
    {
        return string.Compare(x, y, StringComparison.OrdinalIgnoreCase);
    }
}

IList<MyObject> myobj = new List<MyObject>();
var orderedList = myobj.OrderBy(x => x.marker, new CaseInsensitiveComparer()).ToList();
person BrunoLM    schedule 02.10.2010
comment
+1 для учета чувствительности к регистру, но в Framework уже есть нечувствительные к регистру средства сравнения строк, создавать их не нужно. Попробуйте StringComparer.OrdinalIgnoreCase вместо CaseInsensitiveComparer. - person Joe; 02.10.2010

Я бы против использования OrderBy со списком, потому что это метод расширения LINQ, поэтому:

  • Он оборачивает список в перечислимый, затем перечисляет его и заполняет новый временный список, а затем сортирует этот новый список.
  • Он помещает отсортированный список внутрь другого перечислимого типа.
  • Затем, когда вы вызываете ToList(), он выполняет итерацию по нему и заполняет другой новый список элементами.

По сути: он создает и заполняет 2 новых списка и 2 перечисления в дополнение к фактической сортировке. Для сравнения, List.Sort() сортирует на месте и ничего не создает, что делает его более эффективным.

Моя рекомендация была бы такой:

  • Если вы знаете базовый тип, используйте List.Sort() или Array.Sort(array)
  • Если вы не знаете базовый тип, скопируйте список во временный массив, отсортируйте его, используя Array.Sort(array), и верните его.
person Christophe B.    schedule 19.10.2012

OrderBy определенно выполняет свою работу, но я лично предпочитаю синтаксис List.Sort, потому что вы можете передать ему Comparison<T> делегата вместо того, чтобы писать класс, реализующий IComparer<T>. Мы можем достичь этой цели с помощью метода расширения, и если это вам интересно, посмотрите SortExtensions:

http://blog.velir.com/index.php/2011/02/17/ilistt-sorting-a-better-way/.

person David Mills    schedule 18.02.2011

Для объяснения, почему не использовать OrderBy или аналогичный, проверьте ответ Кристофа.

Вот одна из попыток быстрой сортировки:

public static void Sort<T>(this IList<T> ilist)
{
    switch(ilist)
    {
        case List<T> lst:
            lst.Sort();
            break;
        case Array arr:
            Array.Sort(arr);
            break;
        default:
            throw new NotImplementedException();
            // or add slow impl if you don't want this to fail!!
    }
}
person watbywbarif    schedule 30.08.2018

Для сортировки на месте вы, по сути, увидите эти два подхода:

        IList<T> list = .... // your ilist
        var sorted = list.ToArray();
        Array.Sort(sorted);

        for (int i = 0; i < list.Count; i++)
        {
            list[i] = sorted[i];
        }

и

        IList<T> list = .... // your ilist
        ArrayList.Adapter((IList)list).Sort();

Второй вариант может выглядеть проще, но он не подходит для коллекций типов значений, поскольку влечет за собой штрафы за бокс. Более того, нет гарантии, что ваш IList<T> будет реализовывать IList. Первый лучше ИМО.


Вы также можете использовать первый подход для сортировки ICollection<T> на месте , но сомнительно, следует ли вам предоставлять такую ​​функциональность, поскольку контракт ICollection<T> не гарантирует порядок (подумайте о хэш-структурах). В любом случае, чтобы показать вам пример кода:

    ICollection<T> collection = .... // your icollection
    var sorted = collection.ToArray();
    Array.Sort(sorted);

    collection.Clear();
    foreach (var i in sorted)
    {
       collection.Add(i);
    }

Замечание о стабильности сортировки: алгоритмы сортировки массивов / списков .NET нестабильны. Для стабильной сортировки вам нужно будет использовать:

        IList<T> list = .... // your ilist
        var sorted = list.OrderBy(i => i).ToArray();

        for (int i = 0; i < list.Count; i++)
        {
            list[i] = sorted[i];
        }

Это не может быть так быстро, как нестабильные сорта.


Наконец, для полного ответа, возможно, лучше использовать комбинированный подход, принятый watbywbarif:

    public static void Sort<T>(this IList<T> list, IComparer<T> comparer, bool stable)
    {
        if (stable)
        {
            list.StableSort(comparer);
        }
        else
        {
            list.UnstableSort(comparer);
        }
    }

    static void StableSort<T>(this IList<T> list, IComparer<T> comparer)
    {
        list.OrderBy(x => x, comparer).CopyTo(list);
    }

    static void UnstableSort<T>(this IList<T> list, IComparer<T> comparer)
    {
        switch (list)
        {
            case List<T> l:
                l.Sort(comparer);
                break;

            case T[] a:
                Array.Sort(a, comparer);
                break;

            default:
                T[] sortable = list.ToArray();
                sortable.UnstableSort(comparer);
                sortable.CopyTo(list);
                break;
        }
    }

    static void CopyTo<T>(this IEnumerable<T> source, IList<T> target)
    {
        int i = 0;
        foreach (T item in source)
        {
            target[i++] = item;
        }
    }

Это все, что касается встроенных подходов. Для более быстрой реализации вам придется развернуть свой собственный, см. https://stackoverflow.com/a/19167475

person nawfal    schedule 09.08.2020