Итак, сегодня я столкнулся с интересной проблемой. У нас есть веб-служба 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> так же, как и 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)); } // Sorts in IList<T> in place, when T is IComparable<T> public static void Sort<T>(this IList<T> list) where T: IComparable<T> { Comparison<T> comparison = (l, r) => l.CompareTo(r); Sort(list, 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/
источник
ISortableList<T>
интерфейс (с методами для сортировки части списка с использованием некоторого конкретного компаратора),List<T>
реализовать его и иметь статический метод, который мог бы сортировать любойIList<T>
, проверяя, реализован ли он,ISortableList<T>
и, если нет, копирование в массив, сортировка, очисткаIList<T>
и повторное добавление элементов.IList<T> list
может быть приведен к неуниверсальномуIList
интерфейсу. Если вы кодируете свой собственный класс, реализующийIList<T>
интерфейс, убедитесь, что вы также реализуете неуниверсальныйIList
интерфейс, иначе код завершится ошибкой с исключением приведения класса.ISortableList<T>
предложить, чего еще нетIList<T>
? Или, если спросить иначе, почемуIList<T>
нельзя отсортировать элементы на месте без повторного добавления элементов с помощью воображаемого статического метода?IList<T>
интерфейс для доступа к каждому элементу. Разница в скорости достаточно велика, поэтому во многих случаях может быть быстрее скопировать список в массив, отсортировать массив и скопировать список обратно, чем пытаться использовать процедуру сортировки для обработки списка на месте.ComparisonComparer
Класс не является необходимым.Comparer<T>.Create(comparison)
Вместо этого вы можете использовать стандартный статический метод .Я думаю, вам придется сделать что-то подобное (преобразовать в более конкретный тип).
Возможно, возьмите его в список T, а не в ArrayList, чтобы получить безопасность типов и больше возможностей для реализации компаратора.
источник
Принятый ответ @DavidMills неплох, но я думаю, что его можно улучшить. Во-первых, нет необходимости определять
ComparisonComparer<T>
класс, когда фреймворк уже включает статический методComparer<T>.Create(Comparison<T>)
. Этот метод можно использовать для создания файла "IComparison
на лету".Кроме того , он бросает
IList<T>
наIList
который имеет потенциал , чтобы быть опасным. В большинстве случаев, которые я видел,List<T>
какие инструментыIList
используются за кулисами для реализацииIList<T>
, но это не гарантируется и может привести к нестабильному коду.Наконец, перегруженный
List<T>.Sort()
метод имеет 4 сигнатуры, и только 2 из них реализованы.List<T>.Sort()
List<T>.Sort(Comparison<T>)
List<T>.Sort(IComparer<T>)
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
интерфейс.источник
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 одного и того же типа, возвращенные 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(); } } }
источник
Вот пример более строгого набора. Не уверен, что это лучший способ.
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, написанного как обычный статический метод. К сожалению, это довольно некрасиво и многословно.
источник
В VS2008, когда я щелкаю ссылку на службу и выбираю «Настроить ссылку на службу», есть возможность выбрать способ десериализации списков, возвращаемых службой, клиентом.
Примечательно, что я могу выбирать между System.Array, System.Collections.ArrayList и System.Collections.Generic.List.
источник
using System.Linq; var yourList = SomeDAO.GetRandomThings(); yourList.ToList().Sort( (thing, randomThing) => thing.CompareThisProperty.CompareTo( randomThing.CompareThisProperty ) );
Красиво! Гетто.
источник
Нашел хороший пост по этому поводу и подумал, что поделюсь. Посмотрите ЗДЕСЬ
В принципе.
Вы можете создать следующий класс и классы 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();
Результат был: IList B A C
Список A B C
Iist еще раз A B C
источник
Это выглядит НАМНОГО ПРОСТО, если вы спросите меня. Это ОТЛИЧНО работает для меня.
Вы можете использовать Cast (), чтобы изменить его на IList, затем используйте OrderBy ():
var ordered = theIList.Cast<T>().OrderBy(e => e);
ГДЕ T - это тип, например. Model.Employee или Plugin.ContactService.Shared.Contact
Затем вы можете использовать цикл for и его DONE.
ObservableCollection<Plugin.ContactService.Shared.Contact> ContactItems= new ObservableCollection<Contact>(); foreach (var item in ordered) { ContactItems.Add(item); }
источник
Преобразуйте свою коллекцию
IList
вList<T>
или другую общую коллекцию, а затем вы можете легко запросить / отсортировать ее, используяSystem.Linq
пространство имен (оно предоставит множество методов расширения)источник
IList<T>
реализуетIEnumerable<T>
и, следовательно, не требует преобразования для использования операций Linq.