Mam klasy o nazwie Order
, która ma właściwości takie jak OrderId
, OrderDate
, Quantity
, i Total
. Mam listę tej Order
klasy:
List<Order> objListOrder = new List<Order>();
GetOrderList(objListOrder); // fill list of orders
Teraz chcę posortować listę na podstawie jednej właściwości Order
obiektu, na przykład muszę posortować ją według daty zamówienia lub identyfikatora zamówienia.
Jak mogę to zrobić w C #?
Odpowiedzi:
Najprostszym sposobem, jaki mogę wymyślić, jest użycie Linq:
źródło
listWithObjects = listWithObjects.OrderByDescending(o => o.Status).ToList();
wystarczy na takie przedsięwzięcie?Jeśli chcesz posortować listę w miejscu, możesz użyć
Sort
metody, przekazującComparison<T>
delegata:Jeśli wolisz utworzyć nową, posortowaną sekwencję niż sortować w miejscu, możesz użyć
OrderBy
metody LINQ , jak wspomniano w innych odpowiedziach.źródło
x
iy
po prawej stronie strzałki=>
.Nullable<>
(weźmyDateTime?
jako przykład) możesz użyć,.Sort((x, y) => Nullable.Compare(x.OrderDate, y.OrderDate))
który będzie traktował wartość null jako poprzedzającą wszystkie wartości inne niż null. Jest dokładnie taki sam jak.Sort((x, y) => Comparer<DateTime?>.Default.Compare(x.OrderDate, y.OrderDate)
.Aby to zrobić bez LINQ na .Net2.0:
Jeśli korzystasz z .Net3.0, to odpowiedź LukeH jest tym, czego szukasz.
Aby posortować według wielu właściwości, nadal możesz to zrobić w ramach delegata. Na przykład:
Dałoby to rosnące daty z malejącymi porządkami.
Nie zalecałbym jednak trzymania delegatów, ponieważ oznaczałoby to wiele miejsc bez ponownego użycia kodu. Powinieneś wdrożyć
IComparer
i po prostu przekazać to do swojejSort
metody. Zobacz tutaj .A następnie, aby użyć tej klasy IComparer, po prostu utwórz ją i przekaż do metody sortowania:
źródło
IComparer
implementacje, co daje nam zachowanie polimorficzne.Najprostszym sposobem na uporządkowanie listy jest użycie
OrderBy
Jeśli chcesz zamówić według wielu kolumn, takich jak zapytanie SQL.
Aby to osiągnąć, możesz wykonać
ThenBy
następujące czynności.źródło
Robisz to bez Linq, jak powiedziałeś:
Następnie po prostu wywołaj .sort () na liście zamówień
źródło
null
naas
obsadzie. To jest cały sensas
, ponieważ (ha, ha)(Order)obj
zgłasza wyjątek, gdy zawodzi.if(orderToCompare == null) return 1;
.as
zwraca,null
jeśli rzutowanie się nie powiedzie. Ale przynajmniej test zerowy ma rację.List<Order>
więc typ powinien być zgodny zas
2014 roku, więc prawdopodobnie nie napisałeś błędu, tak samo jak unikanie niepotrzebnego polecenia straży :)List<Order>
; ale oboje spotkaliśmy programistę, który nieKlasyczne rozwiązanie obiektowe
Najpierw muszę się przyzwyczaić do niesamowitości LINQ… Teraz, kiedy już to zrobiliśmy
Odmiana odpowiedzi JimmyHoffa. W przypadku generycznych
CompareTo
parametr staje się bezpieczny dla typu.Ta domyślna sortowalność jest oczywiście wielokrotnego użytku. Oznacza to, że każdy klient nie musi redundantnie zapisywać logiki sortowania. Zamiana „1” i „-1” (lub dowolnych operatorów logicznych) odwraca porządek sortowania.
źródło
this
obiekt jest większy niż zero. Do celów sortowania odwołanie do obiektu o wartości zerowej „jest mniejsze niż”this
obiekt. Właśnie w ten sposób zdecydowałem się zdefiniować sposób sortowania wartości null.// Całkowicie ogólne sortowanie do użytku z widokiem siatki
źródło
data.OrderBy()
. Nieco łatwiej niż na nowo wynaleźć koło.Oto ogólna metoda rozszerzenia LINQ, która nie tworzy dodatkowej kopii listy:
Aby go użyć:
Niedawno zbudowałem ten dodatkowy, który akceptuje
ICompare<U>
, abyś mógł dostosować porównanie. Przydało się to, gdy musiałem wykonać naturalny ciąg znaków:źródło
OrderBy
robi to wszystko wewnętrznie.void
metody rozszerzenia w tym duchu:static class Extensions { public static void SortBy<TSource, TKey>(this List<TSource> self, Func<TSource, TKey> keySelector) { self.SortBy(keySelector, Comparer<TKey>.Default); } public static void SortBy<TSource, TKey>(this List<TSource> self, Func<TSource, TKey> keySelector, IComparer<TKey> comparer) { self.Sort((x, y) => comparer.Compare(keySelector(x), keySelector(y))); } }
Można ją uzupełnićSortByDescending
metodą. Komentarze @ Servy dotyczą również mojego kodu!Korzystanie z LINQ
źródło
źródło
Ulepszona wersja Rogera.
Problem z GetDynamicSortProperty polega na tym, że pobierają tylko nazwy właściwości, ale co się stanie, jeśli w GridView użyjemy NavigationProperties? wyśle wyjątek, ponieważ znajdzie wartość null.
Przykład:
„Employee.Company.Name;” ulegnie awarii ... ponieważ pozwala tylko „Nazwa” jako parametr uzyskać jego wartość.
Oto ulepszona wersja, która pozwala nam sortować według właściwości nawigacji.
źródło
Możesz zrobić coś bardziej ogólnego w zakresie wyboru właściwości, a jednocześnie sprecyzować typ, z którego wybierasz, w twoim przypadku „Zamów”:
napisz swoją funkcję jako ogólną:
a następnie użyj go w następujący sposób:
Możesz być jeszcze bardziej ogólny i zdefiniować typ otwarty dla tego, co chcesz zamówić:
i używaj go w ten sam sposób:
Co jest głupim, niepotrzebnym, złożonym sposobem robienia „OrderBy” w stylu LINQ, ale może dać ci wskazówkę, jak można go zaimplementować w sposób ogólny
źródło
Proszę pozwolić mi uzupełnić odpowiedź przez @LukeH z jakimś przykładem kodu, ponieważ go przetestowałem, uważam, że może być przydatny dla niektórych:
źródło
źródło
Skorzystaj z LiNQ
OrderBy
źródło
W oparciu o moduł porównujący GenericTypeTea :
możemy uzyskać większą elastyczność, dodając flagi sortowania:
W tym scenariuszu należy jawnie utworzyć instancję jako MyOrderingClass (zamiast IComparer )
, aby ustawić jej właściwości sortowania:
źródło
Żadna z powyższych odpowiedzi nie była dla mnie wystarczająco ogólna, więc stworzyłem tę:
Uważaj jednak na ogromne zbiory danych. Jest to łatwy kod, ale może sprawić kłopoty, jeśli kolekcja jest ogromna, a typ obiektu kolekcji ma dużą liczbę pól. Czas działania to NxM, gdzie:
N = liczba elementów w kolekcji
M = liczba właściwości w obiekcie
źródło
Każdy, kto pracuje z typami zerowalnymi,
Value
jest zobowiązany do korzystaniaCompareTo
.objListOrder.Sort((x, y) => x.YourNullableType.Value.CompareTo(y.YourNullableType.Value));
źródło
Z punktu widzenia wydajności najlepiej jest użyć posortowanej listy, aby dane były sortowane w miarę dodawania do wyniku. Inne podejścia wymagają co najmniej jednej dodatkowej iteracji danych, a większość tworzy kopię danych, co wpłynie nie tylko na wydajność, ale także na użycie pamięci. Może to nie być problem z kilkoma setkami elementów, ale będzie z tysiącami, szczególnie w usługach, w których wiele jednoczesnych żądań może sortować w tym samym czasie. Spójrz na System.Collections.Generic przestrzeń nazw i wybierz klasę z sortowaniem zamiast List.
I jeśli to możliwe, unikaj ogólnych implementacji wykorzystujących refleksję, może to również powodować problemy z wydajnością.
źródło
Załóżmy, że masz następujący kod, w tym kodzie mamy klasę pasażera z kilkoma właściwościami, na podstawie których chcemy posortować.
Możesz więc zaimplementować swoją strukturę sortowania, używając Delegata składu.
źródło