Вопрос

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

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

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

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

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

Это было полезно?

Решение

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

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

from c in list
orderby c.Engine
select c;

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

Другие советы

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

using System.Linq;

IList<Foo> list = new List<Foo>();
IEnumerable<Foo> sortedEnum = list.OrderBy(f=>f.Bar);
IList<Foo> sortedList = sortedEnum.ToList();

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

Я думаю, что в идеале .NET Framework должна включать метод статической сортировки, который принимает IList<T>, но лучше всего создать свой собственный метод расширения.Не так уж сложно создать пару методов, которые позволят вам сортировать IList<T> как вы бы сортировали список<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/

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

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

Принятый ответ @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 интерфейс.

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

У меня есть два 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.

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

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

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

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

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

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

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

Примечательно, что я могу выбирать между System.Массив, System.Коллекции.Список массивов и Система.Коллекции.Общий.Список

using System.Linq;

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

Это прелестно!гетто.

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

В принципе.

Вы можете создать следующие классы class и 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());

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

Является ли это допустимым решением?

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

В результате было:Список B A C

Список A B C

Я снова перечисляю A B C

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top