Więc dzisiaj natrafiłem na ciekawy problem. Mamy usługę sieci Web WCF, która zwraca IList. Nie było to nic wielkiego, dopóki nie chciałem tego uporządkować.
Okazuje się, że interfejs IList nie ma wbudowanej metody sortowania.
Skończyło się na tym, że użyłem tej ArrayList.Adapter(list).Sort(new MyComparer())
metody do rozwiązania problemu, ale wydawało mi się to trochę „getto”.
Bawiłem się pisaniem metody rozszerzającej, a także dziedziczeniem po IList i implementowaniem własnej metody Sort (), a także rzutowaniem na Listę, ale żadna z nich nie wydawała się zbyt elegancka.
Więc moje pytanie brzmi, czy ktoś ma eleganckie rozwiązanie do sortowania IList
Odpowiedzi:
A co powiesz na używanie LINQ To Objects do sortowania?
Powiedzmy, że masz
IList<Car>
, a samochód miałEngine
właściwość, myślę, że możesz sortować w następujący sposób:from c in list orderby c.Engine select c;
Edycja: musisz być szybki, aby uzyskać odpowiedzi tutaj. Ponieważ przedstawiłem nieco inną składnię niż pozostałe odpowiedzi, zostawię swoją odpowiedź - jednak pozostałe przedstawione odpowiedzi są równie ważne.
źródło
Możesz użyć LINQ:
using System.Linq; IList<Foo> list = new List<Foo>(); IEnumerable<Foo> sortedEnum = list.OrderBy(f=>f.Bar); IList<Foo> sortedList = sortedEnum.ToList();
źródło
To pytanie zainspirowało mnie do napisania wpisu na blogu: http://blog.velir.com/index.php/2011/02/17/ilistt-sorting-a-better-way/
Myślę, że idealnie byłoby, gdyby .NET Framework zawierał statyczną metodę sortowania, która akceptuje IList <T>, ale następną najlepszą rzeczą jest utworzenie własnej metody rozszerzającej. Nie jest trudno stworzyć kilka metod, które pozwolą ci posortować IList <T> tak jak List <T>. Jako bonus możesz przeciążać metodę rozszerzenia LINQ OrderBy przy użyciu tej samej techniki, dzięki czemu niezależnie od tego, czy używasz List.Sort, IList.Sort czy IEnumerable.OrderBy, możesz użyć dokładnie tej samej składni.
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); } }
Dzięki tym rozszerzeniom posortuj swój IList tak samo jak listę:
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));
Więcej informacji znajduje się w poście: http://blog.velir.com/index.php/2011/02/17/ilistt-sorting-a-better-way/
źródło
ISortableList<T>
interfejsu (z metodami do sortowania części listy przy użyciu określonej funkcji porównującej),List<T>
zaimplementowanie go i posiadanie metody statycznej, która mogłaby sortować dowolneIList<T>
, sprawdzając, czy jest zaimplementowana,ISortableList<T>
a jeśli nie, skopiowanie go do tablicy, posortowanie tego, wyczyszczenieIList<T>
i ponowne dodanie elementów.IList<T> list
można rzutować naIList
interfejs inny niż ogólny . Jeśli kodujesz własną klasę implementującąIList<T>
interfejs, upewnij się, że implementujesz równieżIList
interfejs inny niż ogólny , w przeciwnym razie kod zakończy się niepowodzeniem z wyjątkiem rzutowania klasy.ISortableList<T>
zaoferować, czego jeszcze nie maIList<T>
? Albo inaczej, dlaczego nie możnaIList<T>
było posortować na miejscu bez ponownego dodawania elementów za pomocą wyimaginowanej metody statycznej?IList<T>
interfejs, aby uzyskać dostęp do każdego elementu. Różnica w szybkości jest na tyle duża, że w wielu przypadkach szybsze może być skopiowanie listy do tablicy, posortowanie tablicy i skopiowanie listy z powrotem, niż próba wykonania procedury sortowania w miejscu.ComparisonComparer
Klasa nie jest konieczne. Zamiast tego można użyć standardowej metody statycznejComparer<T>.Create(comparison)
.Myślę, że będziesz musiał zrobić coś takiego (zamień to na bardziej konkretny typ).
Może przenieś to do listy T zamiast ArrayList, aby uzyskać bezpieczeństwo typów i więcej opcji implementacji elementu porównującego.
źródło
Przyjęta odpowiedź @DavidMills jest całkiem dobra, ale myślę, że można ją poprawić. Po pierwsze, nie ma potrzeby definiowania
ComparisonComparer<T>
klasy, jeśli framework zawiera już metodę statycznąComparer<T>.Create(Comparison<T>)
. Ta metoda może być używana do tworzeniaIComparison
w locie.Ponadto rzuca,
IList<T>
doIList
którego może być niebezpieczny. W większości przypadków, które widziałem,List<T>
które implementacjeIList
są używane za kulisami do implementacjiIList<T>
, ale nie jest to gwarantowane i może prowadzić do kruchego kodu.Wreszcie przeciążona
List<T>.Sort()
metoda ma 4 sygnatury i tylko 2 z nich są zaimplementowane.List<T>.Sort()
List<T>.Sort(Comparison<T>)
List<T>.Sort(IComparer<T>)
List<T>.Sort(Int32, Int32, IComparer<T>)
Poniższa klasa implementuje wszystkie 4
List<T>.Sort()
sygnaturyIList<T>
interfejsu: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]; } } }
Stosowanie:
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)); }
Pomysł polega na wykorzystaniu funkcjonalności elementu bazowego
List<T>
do obsługi sortowania, gdy tylko jest to możliwe. Ponownie, większośćIList<T>
implementacji, które widziałem, używa tego. W przypadku, gdy źródłowa kolekcja jest innego typu, wróć do tworzenia nowego wystąpieniaList<T>
z elementami z listy wejściowej, użyj jej do sortowania, a następnie skopiuj wyniki z powrotem do listy wejściowej. To zadziała, nawet jeśli lista wejściowa nie implementujeIList
interfejsu.źródło
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));**
źródło
Znalazłem ten wątek, gdy szukałem rozwiązania dokładnego problemu opisanego w oryginalnym poście. Żadna z odpowiedzi nie odpowiadała jednak całkowicie mojej sytuacji. Odpowiedź Brody'ego była dość bliska. Oto moja sytuacja i rozwiązanie, które znalazłem.
Mam dwóch IListów tego samego typu zwróconych przez NHibernate i połączyłem te dwa IList w jeden, stąd potrzeba sortowania.
Jak powiedział Brody, zaimplementowałem ICompare na obiekcie (ReportFormat), który jest typem mojego IList:
public class FormatCcdeSorter:IComparer<ReportFormat> { public int Compare(ReportFormat x, ReportFormat y) { return x.FormatCode.CompareTo(y.FormatCode); } }
Następnie konwertuję scalony IList na tablicę tego samego typu:
ReportFormat[] myReports = new ReportFormat[reports.Count]; //reports is the merged IList
Następnie posortuj tablicę:
Array.Sort(myReports, new FormatCodeSorter());//sorting using custom comparer
Ponieważ jednowymiarowa tablica implementuje interfejs
System.Collections.Generic.IList<T>
, tablica może być używana tak jak oryginalna IList.źródło
Przydatna do sortowania według siatki. Ta metoda sortuje listę na podstawie nazw właściwości. Postępuj zgodnie z przykładem.
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(); } } }
źródło
Oto przykład użycia silniejszego pisania. Nie jestem jednak pewien, czy to koniecznie najlepszy sposób.
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; } }
Funkcja Cast to po prostu reimplementacja metody rozszerzającej, która jest dostarczana z 3.5 zapisanym jako normalna metoda statyczna. Jest to niestety dość brzydkie i rozwlekłe.
źródło
W VS2008, kiedy klikam odwołanie do usługi i wybieram opcję „Konfiguruj odwołanie do usługi”, istnieje opcja wyboru sposobu, w jaki klient deserializuje listy zwracane przez usługę.
W szczególności mogę wybierać między System.Array, System.Collections.ArrayList i System.Collections.Generic.List
źródło
using System.Linq; var yourList = SomeDAO.GetRandomThings(); yourList.ToList().Sort( (thing, randomThing) => thing.CompareThisProperty.CompareTo( randomThing.CompareThisProperty ) );
To ładne! Getto.
źródło
Znalazłem dobry post na ten temat i pomyślałem, że się nim podzielę. Sprawdź to TUTAJ
Gruntownie.
Możesz utworzyć następujące klasy i klasy 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); } }
Jeśli masz IList, możesz to posortować w ten sposób.
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());
Ale sprawdź tę stronę, aby uzyskać więcej informacji ... Sprawdź to TUTAJ
źródło
Czy to prawidłowe rozwiązanie?
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();
Wynik był następujący: IList B A C
Lista A B C
IList ponownie A B C
źródło
To wygląda O WIELE BARDZIEJ PROSTEJ, jeśli o mnie chodzi. U mnie to działa IDEALNIE.
Możesz użyć Cast (), aby zmienić go na IList, a następnie użyć OrderBy ():
var ordered = theIList.Cast<T>().OrderBy(e => e);
GDZIE T to typ np. Model.Employee lub Plugin.ContactService.Shared.Contact
Następnie możesz użyć pętli for i jej DONE.
ObservableCollection<Plugin.ContactService.Shared.Contact> ContactItems= new ObservableCollection<Contact>(); foreach (var item in ordered) { ContactItems.Add(item); }
źródło
Przekonwertuj swoją kolekcję
IList
naList<T>
lub inną ogólną kolekcję, a następnie możesz łatwo przeszukiwać / sortować ją za pomocąSystem.Linq
przestrzeni nazw (dostarczy kilka metod rozszerzających)źródło
IList<T>
implementujeIEnumerable<T>
i dlatego nie trzeba go konwertować, aby używać operacji Linq.