Сведения о вопросе

SOON

08:11, 8th August, 2020

Теги

c#   generics   sorting   ilist    

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

Просмотров: 510   Ответов: 14

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

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

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

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

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



  Сведения об ответе

ASSembler

02:16, 13th August, 2020

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

using System.Linq;

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


  Сведения об ответе

прога

15:04, 20th August, 2020

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

Я думаю, что в идеале фреймворк .NET будет включать в себя статический метод сортировки, который принимает 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/


  Сведения об ответе

lourence

11:56, 14th August, 2020

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

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

from c in list
orderby c.Engine
select c;

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


  Сведения об ответе

screen

06:54, 18th August, 2020

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

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


  Сведения об ответе

DINO

11:25, 17th August, 2020

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


  Сведения об ответе

lesha

03:52, 9th August, 2020

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

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


  Сведения об ответе

DINO

08:48, 23rd August, 2020

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

У меня есть два ILists одного типа, возвращенных 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.


  Сведения об ответе

VCe znayu

13:56, 17th August, 2020

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


  Сведения об ответе

lool

06:20, 16th August, 2020

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


  Сведения об ответе

prince

07:19, 12th August, 2020

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

        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 Б Один C

Список Один Б C

Опять IList Один Б C


  Сведения об ответе

DINO

14:37, 17th August, 2020

using System.Linq;

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

Это очень мило !трущобы.


  Сведения об ответе

SEEYOU

02:03, 13th August, 2020

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

В основном.

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

Но проверьте этот сайт для получения дополнительной информации... Проверьте это HERE


  Сведения об ответе

SSESION

22:07, 4th August, 2020

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

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, записанным как обычный статический метод. К сожалению, он довольно уродлив и многословен.


  Сведения об ответе

прога

13:08, 23rd August, 2020

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

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


Ответить на вопрос

Чтобы ответить на вопрос вам нужно войти в систему или зарегистрироваться