Итак, я столкнулся с интересной проблемой сегодня. У нас есть веб-сервис 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;
Изменить: Вам нужно быть быстрым, чтобы получить ответы здесь. Поскольку я представил немного другой синтаксис к другим ответам, я оставлю свой ответ - однако, другие представленные ответы одинаково действительны.
Я думаю, вам придется сделать что-то подобное (преобразовать его в более конкретный тип).
Возможно, возьмите его в список T, а не ArrayList, чтобы получить безопасность типов и больше возможностей для реализации компаратора.
Конвертируйте вашу коллекцию IList
в List<T>
какую-либо или какую-либо другую универсальную коллекцию, и затем вы можете легко запросить / отсортировать ее, используя System.Linq
пространство имен (оно предоставит множество методов расширения)
IList<T>
реализует IEnumerable<T>
и, следовательно, не нуждается в преобразовании для использования операций Linq. Вы можете использовать LINQ:
using System.Linq;
IList<Foo> list = new List<Foo>();
IEnumerable<Foo> sortedEnum = list.OrderBy(f=>f.Bar);
IList<Foo> sortedList = sortedEnum.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
Нашел хороший пост по этому поводу и думал, что поделюсь. Проверьте это ЗДЕСЬ
В принципе.
Вы можете создать следующий класс и классы 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());
Но закажите этот сайт для получения дополнительной информации ... Проверьте это ЗДЕСЬ
using System.Linq;
var yourList = SomeDAO.GetRandomThings();
yourList.ToList().Sort( (thing, randomThing) => thing.CompareThisProperty.CompareTo( randomThing.CompareThisProperty ) );
Это мило! Гетто.
Нашел эту ветку, пока искал решение точной проблемы, описанной в оригинальном посте. Однако ни один из ответов полностью не отвечал моей ситуации. Ответ Броди был довольно близок. Вот моя ситуация и решение, которое я нашел.
У меня есть два 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.
Это правильное решение?
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
Полезно для сортировки сетки, этот метод сортирует список по именам свойств. Как следовать примеру.
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();
}
}
}
Этот вопрос вдохновил меня написать сообщение в блоге: 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/
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>
интерфейс для доступа к каждому элементу. Разница в скорости достаточно велика, так что во многих случаях может быть быстрее скопировать список в массив, отсортировать массив и скопировать обратно, чем пытаться создать процедуру сортировки списка на месте. 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));**
Принятый ответ @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
интерфейс.
Это выглядит намного проще, если вы спросите меня. Это работает ОТЛИЧНО для меня.
Вы можете использовать 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);
}