Сортировка IList в C #

Итак, я столкнулся с интересной проблемой сегодня. У нас есть веб-сервис WCF, который возвращает IList. Ничего страшного, пока я не захотел разобраться.

Оказывается, в интерфейсе IList нет встроенного метода сортировки.

Я ArrayList.Adapter(list).Sort(new MyComparer())решил использовать метод для решения проблемы, но мне это показалось немного «гетто».

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

Поэтому мой вопрос: есть ли у кого-нибудь элегантное решение для сортировки IList?

19.08.2008 01:23:04
Зачем вам возвращать IList в первую очередь? Из службы WCF?
DaeMoohn 18.02.2011 15:42:20
15 ОТВЕТОВ
РЕШЕНИЕ

Как насчет использования LINQ To Objects для сортировки для вас?

Скажем, у вас есть IList<Car>, и у машины есть Engineсобственность, я полагаю, вы могли бы отсортировать следующее:

from c in list
orderby c.Engine
select c;

Изменить: Вам нужно быть быстрым, чтобы получить ответы здесь. Поскольку я представил немного другой синтаксис к другим ответам, я оставлю свой ответ - однако, другие представленные ответы одинаково действительны.

54
19.08.2008 01:41:02
Это создаст новое перечислимое, что может быть нежелательно в некоторых сценариях. Вы не можете сортировать IList <T> на месте через интерфейс, кроме как с помощью метода ArrayList.Adapter, насколько мне известно.
Tanveer Badar 28.08.2014 11:11:38

Я думаю, вам придется сделать что-то подобное (преобразовать его в более конкретный тип).

Возможно, возьмите его в список T, а не ArrayList, чтобы получить безопасность типов и больше возможностей для реализации компаратора.

9
19.08.2008 01:29:10

Конвертируйте вашу коллекцию IListв List<T>какую-либо или какую-либо другую универсальную коллекцию, и затем вы можете легко запросить / отсортировать ее, используя System.Linqпространство имен (оно предоставит множество методов расширения)

0
20.09.2015 12:41:19
IList<T>реализует IEnumerable<T>и, следовательно, не нуждается в преобразовании для использования операций Linq.
Steve Guidi 13.07.2010 22:43:17

Вы можете использовать LINQ:

using System.Linq;

IList<Foo> list = new List<Foo>();
IEnumerable<Foo> sortedEnum = list.OrderBy(f=>f.Bar);
IList<Foo> sortedList = sortedEnum.ToList();
65
19.08.2008 01:34:07

Вот пример использования более сильного набора текста. Не уверен, что это лучший способ.

static void Main(string[] args)
{
    IList list = new List<int>() { 1, 3, 2, 5, 4, 6, 9, 8, 7 };
    List<int> stronglyTypedList = new List<int>(Cast<int>(list));
    stronglyTypedList.Sort();
}

private static IEnumerable<T> Cast<T>(IEnumerable list)
{
    foreach (T item in list)
    {
        yield return item;
    }
}

Функция Cast - это просто переопределение метода расширения, поставляемого с 3.5, написанного как обычный статический метод. Это довольно некрасиво и многословно, к сожалению.

0
19.08.2008 11:38:30

В VS2008, когда я щелкаю ссылку на службу и выбираю «Настроить ссылку на службу», появляется возможность выбрать способ десериализации клиентом списков, возвращаемых из службы.

В частности, я могу выбирать между System.Array, System.Collections.ArrayList и System.Collections.Generic.List

0
17.09.2008 13:33:55

Нашел хороший пост по этому поводу и думал, что поделюсь. Проверьте это ЗДЕСЬ

В принципе.

Вы можете создать следующий класс и классы IComparer

public class Widget {
    public string Name = string.Empty;
    public int Size = 0;

    public Widget(string name, int size) {
    this.Name = name;
    this.Size = size;
}
}

public class WidgetNameSorter : IComparer<Widget> {
    public int Compare(Widget x, Widget y) {
        return x.Name.CompareTo(y.Name);
}
}

public class WidgetSizeSorter : IComparer<Widget> {
    public int Compare(Widget x, Widget y) {
    return x.Size.CompareTo(y.Size);
}
}

Тогда, если у вас есть IList, вы можете отсортировать его следующим образом.

List<Widget> widgets = new List<Widget>();
widgets.Add(new Widget("Zeta", 6));
widgets.Add(new Widget("Beta", 3));
widgets.Add(new Widget("Alpha", 9));

widgets.Sort(new WidgetNameSorter());
widgets.Sort(new WidgetSizeSorter());

Но закажите этот сайт для получения дополнительной информации ... Проверьте это ЗДЕСЬ

0
23.08.2010 09:14:26
using System.Linq;

var yourList = SomeDAO.GetRandomThings();
yourList.ToList().Sort( (thing, randomThing) => thing.CompareThisProperty.CompareTo( randomThing.CompareThisProperty ) );

Это мило! Гетто.

0
6.07.2009 13:50:17

Нашел эту ветку, пока искал решение точной проблемы, описанной в оригинальном посте. Однако ни один из ответов полностью не отвечал моей ситуации. Ответ Броди был довольно близок. Вот моя ситуация и решение, которое я нашел.

У меня есть два IList одного и того же типа, возвращенных NHibernate, и я превратил два IList в один, следовательно, необходима сортировка.

Как сказал Броди, я реализовал ICompare для объекта (ReportFormat), который является типом моего IList:

 public class FormatCcdeSorter:IComparer<ReportFormat>
    {
       public int Compare(ReportFormat x, ReportFormat y)
        {
           return x.FormatCode.CompareTo(y.FormatCode);
        }
    }

Затем я преобразовываю объединенный IList в массив того же типа:

ReportFormat[] myReports = new ReportFormat[reports.Count]; //reports is the merged IList

Затем отсортируйте массив:

Array.Sort(myReports, new FormatCodeSorter());//sorting using custom comparer

Поскольку одномерный массив реализует интерфейс System.Collections.Generic.IList<T>, массив можно использовать так же, как и исходный IList.

1
13.07.2010 22:20:19

Это правильное решение?

        IList<string> ilist = new List<string>();
        ilist.Add("B");
        ilist.Add("A");
        ilist.Add("C");

        Console.WriteLine("IList");
        foreach (string val in ilist)
            Console.WriteLine(val);
        Console.WriteLine();

        List<string> list = (List<string>)ilist;
        list.Sort();
        Console.WriteLine("List");
        foreach (string val in list)
            Console.WriteLine(val);
        Console.WriteLine();

        list = null;

        Console.WriteLine("IList again");
        foreach (string val in ilist)
            Console.WriteLine(val);
        Console.WriteLine();

Результат был: IList B A C

Список A B C

IList снова A B C

0
11.09.2010 14:10:14
Действительно, если это действительно список <T>. В некоторых случаях у вас есть другие типы, реализующие IList <T> (например, простой массив), где downcast не будет работать. Жаль, что метод Sort () не является методом расширения для IList <T>.
Cygon 5.01.2012 13:32:03

Полезно для сортировки сетки, этот метод сортирует список по именам свойств. Как следовать примеру.

    List<MeuTeste> temp = new List<MeuTeste>();

    temp.Add(new MeuTeste(2, "ramster", DateTime.Now));
    temp.Add(new MeuTeste(1, "ball", DateTime.Now));
    temp.Add(new MeuTeste(8, "gimm", DateTime.Now));
    temp.Add(new MeuTeste(3, "dies", DateTime.Now));
    temp.Add(new MeuTeste(9, "random", DateTime.Now));
    temp.Add(new MeuTeste(5, "call", DateTime.Now));
    temp.Add(new MeuTeste(6, "simple", DateTime.Now));
    temp.Add(new MeuTeste(7, "silver", DateTime.Now));
    temp.Add(new MeuTeste(4, "inn", DateTime.Now));

    SortList(ref temp, SortDirection.Ascending, "MyProperty");

    private void SortList<T>(
    ref List<T> lista
    , SortDirection sort
    , string propertyToOrder)
    {
        if (!string.IsNullOrEmpty(propertyToOrder)
        && lista != null
        && lista.Count > 0)
        {
            Type t = lista[0].GetType();

            if (sort == SortDirection.Ascending)
            {
                lista = lista.OrderBy(
                    a => t.InvokeMember(
                        propertyToOrder
                        , System.Reflection.BindingFlags.GetProperty
                        , null
                        , a
                        , null
                    )
                ).ToList();
            }
            else
            {
                lista = lista.OrderByDescending(
                    a => t.InvokeMember(
                        propertyToOrder
                        , System.Reflection.BindingFlags.GetProperty
                        , null
                        , a
                        , null
                    )
                ).ToList();
            }
        }
    }
1
8.12.2010 13:55:04

Этот вопрос вдохновил меня написать сообщение в блоге: http://blog.velir.com/index.php/2011/02/17/ilistt-sorting-a-better-way/

Я думаю, что в идеале .NET Framework должен включать статический метод сортировки, который принимает IList <T>, но следующая лучшая вещь - это создать собственный метод расширения. Нетрудно создать пару методов, которые позволят вам сортировать IList <T>, как если бы вы использовали List <T>. В качестве бонуса вы можете перегрузить метод расширения LINQ OrderBy, используя ту же технику, так что независимо от того, используете ли вы List.Sort, IList.Sort или IEnumerable.OrderBy, вы можете использовать точно такой же синтаксис.

public static class SortExtensions
{
    //  Sorts an IList<T> in place.
    public static void Sort<T>(this IList<T> list, Comparison<T> comparison)
    {
        ArrayList.Adapter((IList)list).Sort(new ComparisonComparer<T>(comparison));
    }

    // Convenience method on IEnumerable<T> to allow passing of a
    // Comparison<T> delegate to the OrderBy method.
    public static IEnumerable<T> OrderBy<T>(this IEnumerable<T> list, Comparison<T> comparison)
    {
        return list.OrderBy(t => t, new ComparisonComparer<T>(comparison));
    }
}

// Wraps a generic Comparison<T> delegate in an IComparer to make it easy
// to use a lambda expression for methods that take an IComparer or IComparer<T>
public class ComparisonComparer<T> : IComparer<T>, IComparer
{
    private readonly Comparison<T> _comparison;

    public ComparisonComparer(Comparison<T> comparison)
    {
        _comparison = comparison;
    }

    public int Compare(T x, T y)
    {
        return _comparison(x, y);
    }

    public int Compare(object o1, object o2)
    {
        return _comparison((T)o1, (T)o2);
    }
}

С этими расширениями сортируйте свой IList так же, как список.

IList<string> iList = new []
{
    "Carlton", "Alison", "Bob", "Eric", "David"
};

// Use the custom extensions:

// Sort in-place, by string length
iList.Sort((s1, s2) => s1.Length.CompareTo(s2.Length));

// Or use OrderBy()
IEnumerable<string> ordered = iList.OrderBy((s1, s2) => s1.Length.CompareTo(s2.Length));

Там больше информации в посте: http://blog.velir.com/index.php/2011/02/17/ilistt-sorting-a-better-way/

59
18.02.2011 15:39:47
Правильный подход действительно состоял бы в том, чтобы предложить ISortableList<T>интерфейс (с методами для сортировки части списка, используя некоторый конкретный компаратор), List<T>реализовать его и иметь статический метод, который мог бы сортировать любой IList<T>, проверяя, реализован ли он, ISortableList<T>и, если нет, копирование в массив, сортировка, очистка IList<T>и повторное добавление элементов.
supercat 28.09.2012 23:32:22
Прекрасный ответ! Однако, предостережение: этот подход предполагает, что он IList<T> listможет быть приведен к неуниверсальному IListинтерфейсу. Если вы кодируете свой собственный класс, реализующий IList<T>интерфейс, убедитесь, что вы также реализовали неуниверсальный IListинтерфейс, иначе код завершится ошибкой с исключением приведения класса.
sstan 15.12.2015 14:12:14
@supercat: Что может ISortableList<T>предложить то, чего еще нет IList<T>? Или, по-другому, почему IList<T>нельзя отсортировать на месте без повторного добавления элементов вашим воображаемым статическим методом?
O. R. Mapper 22.11.2019 19:19:38
@ORMapper: Если список использует массив в качестве резервного хранилища (обычное, но не обязательное), процедура сортировки, которая напрямую обращается к элементам массива, может быть намного быстрее, чем та, которая должна пройти через IList<T>интерфейс для доступа к каждому элементу. Разница в скорости достаточно велика, так что во многих случаях может быть быстрее скопировать список в массив, отсортировать массив и скопировать обратно, чем пытаться создать процедуру сортировки списка на месте.
supercat 22.11.2019 19:29:08
try this  **USE ORDER BY** :

   public class Employee
    {
        public string Id { get; set; }
        public string Name { get; set; }
    }

 private static IList<Employee> GetItems()
        {
            List<Employee> lst = new List<Employee>();

            lst.Add(new Employee { Id = "1", Name = "Emp1" });
            lst.Add(new Employee { Id = "2", Name = "Emp2" });
            lst.Add(new Employee { Id = "7", Name = "Emp7" });
            lst.Add(new Employee { Id = "4", Name = "Emp4" });
            lst.Add(new Employee { Id = "5", Name = "Emp5" });
            lst.Add(new Employee { Id = "6", Name = "Emp6" });
            lst.Add(new Employee { Id = "3", Name = "Emp3" });

            return lst;
        }

**var lst = GetItems().AsEnumerable();

            var orderedLst = lst.OrderBy(t => t.Id).ToList();

            orderedLst.ForEach(emp => Console.WriteLine("Id - {0} Name -{1}", emp.Id, emp.Name));**
1
31.08.2012 08:02:56

Принятый ответ @DavidMills довольно хороший, но я думаю, что его можно улучшить. Во-первых, нет необходимости определять ComparisonComparer<T>класс, когда инфраструктура уже содержит статический метод Comparer<T>.Create(Comparison<T>). Этот метод может быть использован для создания IComparisonна лету.

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

Наконец, перегруженный List<T>.Sort()метод имеет 4 подписи, и только 2 из них реализованы.

  1. List<T>.Sort()
  2. List<T>.Sort(Comparison<T>)
  3. List<T>.Sort(IComparer<T>)
  4. List<T>.Sort(Int32, Int32, IComparer<T>)

Класс ниже реализует все 4 List<T>.Sort()подписи для IList<T>интерфейса:

using System;
using System.Collections.Generic;

public static class IListExtensions
{
    public static void Sort<T>(this IList<T> list)
    {
        if (list is List<T>)
        {
            ((List<T>)list).Sort();
        }
        else
        {
            List<T> copy = new List<T>(list);
            copy.Sort();
            Copy(copy, 0, list, 0, list.Count);
        }
    }

    public static void Sort<T>(this IList<T> list, Comparison<T> comparison)
    {
        if (list is List<T>)
        {
            ((List<T>)list).Sort(comparison);
        }
        else
        {
            List<T> copy = new List<T>(list);
            copy.Sort(comparison);
            Copy(copy, 0, list, 0, list.Count);
        }
    }

    public static void Sort<T>(this IList<T> list, IComparer<T> comparer)
    {
        if (list is List<T>)
        {
            ((List<T>)list).Sort(comparer);
        }
        else
        {
            List<T> copy = new List<T>(list);
            copy.Sort(comparer);
            Copy(copy, 0, list, 0, list.Count);
        }
    }

    public static void Sort<T>(this IList<T> list, int index, int count,
        IComparer<T> comparer)
    {
        if (list is List<T>)
        {
            ((List<T>)list).Sort(index, count, comparer);
        }
        else
        {
            List<T> range = new List<T>(count);
            for (int i = 0; i < count; i++)
            {
                range.Add(list[index + i]);
            }
            range.Sort(comparer);
            Copy(range, 0, list, index, count);
        }
    }

    private static void Copy<T>(IList<T> sourceList, int sourceIndex,
        IList<T> destinationList, int destinationIndex, int count)
    {
        for (int i = 0; i < count; i++)
        {
            destinationList[destinationIndex + i] = sourceList[sourceIndex + i];
        }
    }
}

Использование:

class Foo
{
    public int Bar;

    public Foo(int bar) { this.Bar = bar; }
}

void TestSort()
{
    IList<int> ints = new List<int>() { 1, 4, 5, 3, 2 };
    IList<Foo> foos = new List<Foo>()
    {
        new Foo(1),
        new Foo(4),
        new Foo(5),
        new Foo(3),
        new Foo(2),
    };

    ints.Sort();
    foos.Sort((x, y) => Comparer<int>.Default.Compare(x.Bar, y.Bar));
}

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

4
5.05.2018 19:49:58

Это выглядит намного проще, если вы спросите меня. Это работает ОТЛИЧНО для меня.

Вы можете использовать Cast (), чтобы изменить его на IList, затем использовать OrderBy ():

    var ordered = theIList.Cast<T>().OrderBy(e => e);

ГДЕ Т это тип например. Model.Employee или Plugin.ContactService.Shared.Contact

Затем вы можете использовать цикл for и его готово.

  ObservableCollection<Plugin.ContactService.Shared.Contact> ContactItems= new ObservableCollection<Contact>();

    foreach (var item in ordered)
    {
       ContactItems.Add(item);
    }
0
2.11.2019 09:13:56