Kaip rūšiuoti <T> sąrašą pagal objektą

Turiu klasę, vadinamą „ Order , turinčią tokias savybes kaip „ OrderId , „ OrderDate , „ Quantity ir „ Total . Turiu šio Order klasės sąrašą:

 List<Order> objListOrder = new List<Order>(); GetOrderList(objListOrder); // fill list of orders 

Dabar noriu surūšiuoti sąrašą, remiantis viena Order objekto ypatybe, pvz., Turiu rūšiuoti jį pagal užsakymo datą arba užsakymo ID.

Kaip tai padaryti C #?

937
22 июля '10 в 16:13 2010-07-22 16:13 „Shyju“ yra nustatytas liepos 22 d., 10:13, 2010-07-22 16:13
@ 19 atsakymų

Paprasčiausias būdas man galvoti yra naudoti „Linq“:

 List<Order> SortedList = objListOrder.OrderBy(o=>o.OrderDate).ToList(); 
1377
22 июля '10 в 16:16 2010-07-22 16:16 atsakymas suteikiamas Lozorui liepos 22 d., 10 val. 16:16 2010-07-22 16:16

Jei norite surūšiuoti sąrašą vietoje, galite naudoti Sort metodą, perduodami Comparison<T> delegatą:

 objListOrder.Sort((x, y) => x.OrderDate.CompareTo(y.OrderDate)); 

Jei norite sukurti naują, surūšiuotą seką, o ne surūšiuoti, galite naudoti LINQ metodą OrderBy , kaip aprašyta kituose atsakymuose.

527
22 июля '10 в 16:23 2010-07-22 16:23 atsakymą pateikė LukeH liepos 22 d., 10 d., 16:23, 2010-07-22 16:23

Norėdami tai padaryti be LINQ .Net2.0:

 List<Order> objListOrder = GetOrderList(); objListOrder.Sort( delegate(Order p1, Order p2) { return p1.OrderDate.CompareTo(p2.OrderDate); } ); 

Jei esate .Net3.0, tada LukeH atsakymas yra tas, ko jums reikia.

Jei norite surūšiuoti keletą savybių, vis tiek galite tai atlikti per delegatą. Pavyzdžiui:

 orderList.Sort( delegate(Order p1, Order p2) { int compareDate = p1.Date.CompareTo(p2.Date); if (compareDate == 0) { return p2.OrderID.CompareTo(p1.OrderID); } return compareDate; } ); 

Tai suteiks jums didėjančias datas su mažėjančia tvarka.

Tačiau nenorėčiau rekomenduoti laikytis delegatų, nes tai reikštų daug vietų be pakartotinio kodo naudojimo. Jūs turite įdiegti „ IComparer ir paprasčiausiai perduoti jį per „ Sort metodą. Žiūrėkite čia .

 public class MyOrderingClass : IComparer<Order> { public int Compare(Order x, Order y) { int compareDate = x.Date.CompareTo(y.Date); if (compareDate == 0) { return x.OrderID.CompareTo(y.OrderID); } return compareDate; } } 

Ir tada, jei norite naudoti šią „IComparer“ klasę, tiesiog sukurkite egzempliorių ir persiųskite jį į rūšiavimo metodą:

 IComparer<Order> comparer = new MyOrderingClass(); orderList.Sort(comparer); 
202
22 июля '10 в 16:35 2010-07-22 16:35 atsakymas pateikiamas „ GenericTypeTea“ liepos 22 d., 10 val. 16:35 2010-07-22 16:35

UžsakytiBeiti į užsakymų sąrašą - naudokite „ OrderBy

  List<Order> objListOrder = source.OrderBy(order => order.OrderDate).ToList(); 

Jei norite užsisakyti kelis stulpelius, pvz., Šią SQL užklausą.

 ORDER BY OrderDate, OrderId 

Tam jūs galite naudoti ThenBy kaip ThenBy žemiau.

  List<Order> objListOrder = source.OrderBy(order => order.OrderDate).ThenBy(order => order.OrderId).ToList(); 
79
22 июля '10 в 16:23 2010-07-22 16:23 atsakymą pateikė PSK liepos 10 d., 16:23, 2010-07-22 16:23

Tai darote be „Linq“, kaip sakėte:

 public class Order : IComparable { public DateTime OrderDate { get; set; } public int OrderId { get; set; } public int CompareTo(object obj) { Order orderToCompare = obj as Order; if (orderToCompare.OrderDate < OrderDate || orderToCompare.OrderId < OrderId) { return 1; } if (orderToCompare.OrderDate > OrderDate || orderToCompare.OrderId > OrderId) { return -1; } // The orders are equivalent. return 0; } } 

Tada skambinkite .sort () į savo užsakymų sąrašą.

31
22 июля '10 в 16:55 2010-07-22 16:55 Atsakymą pateikė Jimmy Hoffa liepos 10 d. 10 val. 16:55 2010-07-22 16:55

Klasikinis į objektą orientuotas sprendimas

Pirmiausia turiu išlenkti LINQ awesomeness ... Dabar, kai mes ją turime,

Pasirinkimas atsako į Jimmy Hoff. Su generiniais vaistais CompareTo parametras tampa tipo saugu.

 public class Order : IComparable<Order> { public int CompareTo( Order that ) { if ( that == null ) return 1; if ( this.OrderDate > that.OrderDate) return 1; if ( this.OrderDate < that.OrderDate) return -1; return 0; } } // in the client code // assume myOrders is a populated List<Order> myOrders.Sort(); 

Šis numatytasis rūšiavimas yra pakartotinai naudojamas. Tai reiškia, kad kiekvienam klientui nereikia perrašyti rūšiavimo logikos. Perjungus „1“ ir „-1“ (arba loginius operatorius, jūsų pasirinkimas) atšaukiama rūšiavimo tvarka.

21
16 окт. atsakymą radarbob pateikė spalio 16 d. 2014-10-16 17:03 '14, 17:03, 2014-10-16 17:03

// Visiškai bendro pobūdžio rūšiavimas, skirtas naudoti su gridview

 public List<T> Sort_List<T>(string sortDirection, string sortExpression, List<T> data) { List<T> data_sorted = new List<T>(); if (sortDirection == "Ascending") { data_sorted = (from n in data orderby GetDynamicSortProperty(n, sortExpression) ascending select n).ToList(); } else if (sortDirection == "Descending") { data_sorted = (from n in data orderby GetDynamicSortProperty(n, sortExpression) descending select n).ToList(); } return data_sorted; } public object GetDynamicSortProperty(object item, string propName) { //Use reflection to get order type return item.GetType().GetProperty(propName).GetValue(item, null); } 
15
13 июня '13 в 4:37 2013-06-13 04:37 atsakymas pateikiamas rogerį birželio 13 d. 13 val. 2013-06-13 04:37

Čia yra bendras LINQ plėtinio metodas, kuris nesukuria papildomos sąrašo kopijos:

 public static void Sort<T,U>(this List<T> list, Func<T, U> expression) where U : IComparable<U> { list.Sort((x, y) => expression.Invoke(x).CompareTo(expression.Invoke(y))); } 

Norėdami jį naudoti:

 myList.Sort(x=> x.myProperty); 

Neseniai ICompare<U> šį papildomą ICompare<U> , kuris užima „ ICompare<U> , todėl galite tinkinti palyginimą. Tai buvo naudinga, kai man reikėjo padaryti natūralią eilutę:

 public static void Sort<T, U>(this List<T> list, Func<T, U> expression, IComparer<U> comparer) where U : IComparable<U> { list.Sort((x, y) => comparer.Compare(expression.Invoke(x), expression.Invoke(y))); } 
5
14 февр. Petras pateikė atsakymą vasario 14 d. 2014-02-14 17:25 '14, 17:25 pm 2014-02-14 17:25

Patobulinta Roger versija.

„GetDynamicSortProperty“ problema yra ta, kad jūs gaunate nuosavybės pavadinimus, bet kas atsitiks, jei naudosime „NavigationProperties“ „GridView“? ji išsiųs išimtį, nes ji nustato nulį.

Pavyzdys:

"Darbuotojas. Įmonės pavadinimas." bus nesėkmingas ... nes jis leidžia jums gauti tik „vardo“ vertę kaip parametrą.

Čia yra patobulinta versija, leidžianti mums rūšiuoti pagal navigacijos savybes.

 public object GetDynamicSortProperty(object item, string propName) { try { string[] prop = propName.Split('.'); //Use reflection to get order type int i = 0; while (i < prop.Count()) { item = item.GetType().GetProperty(prop[i]).GetValue(item, null); i++; } return item; } catch (Exception ex) { throw ex; } } 
3
04 июля '13 в 17:32 2013-07-04 17:32 atsakymas pateiktas vartotojo1013375 liepos 4 d., „13, 17:32 2013-07-04 17:32

Leiskite man užpildyti @LukeH atsakymą su tam tikru pavyzdiniu kodu, kaip jį išbandžiau. Manau, kad tai gali būti naudinga kai kuriems:

 public class Order { public string OrderId { get; set; } public DateTime OrderDate { get; set; } public int Quantity { get; set; } public int Total { get; set; } public Order(string orderId, DateTime orderDate, int quantity, int total) { OrderId = orderId; OrderDate = orderDate; Quantity = quantity; Total = total; } } public void SampleDataAndTest() { List<Order> objListOrder = new List<Order>(); objListOrder.Add(new Order("tu me paulo ", Convert.ToDateTime("01/06/2016"), 1, 44)); objListOrder.Add(new Order("ante laudabas", Convert.ToDateTime("02/05/2016"), 2, 55)); objListOrder.Add(new Order("ad ordinem ", Convert.ToDateTime("03/04/2016"), 5, 66)); objListOrder.Add(new Order("collocationem ", Convert.ToDateTime("04/03/2016"), 9, 77)); objListOrder.Add(new Order("que rerum ac ", Convert.ToDateTime("05/02/2016"), 10, 65)); objListOrder.Add(new Order("locorum ; cuius", Convert.ToDateTime("06/01/2016"), 1, 343)); Console.WriteLine("Sort the list by date ascending:"); objListOrder.Sort((x, y) => x.OrderDate.CompareTo(y.OrderDate)); foreach (Order o in objListOrder) Console.WriteLine("OrderId = " + o.OrderId + " OrderDate = " + o.OrderDate.ToString() + " Quantity = " + o.Quantity + " Total = " + o.Total); Console.WriteLine("Sort the list by date descending:"); objListOrder.Sort((x, y) => y.OrderDate.CompareTo(x.OrderDate)); foreach (Order o in objListOrder) Console.WriteLine("OrderId = " + o.OrderId + " OrderDate = " + o.OrderDate.ToString() + " Quantity = " + o.Quantity + " Total = " + o.Total); Console.WriteLine("Sort the list by OrderId ascending:"); objListOrder.Sort((x, y) => x.OrderId.CompareTo(y.OrderId)); foreach (Order o in objListOrder) Console.WriteLine("OrderId = " + o.OrderId + " OrderDate = " + o.OrderDate.ToString() + " Quantity = " + o.Quantity + " Total = " + o.Total); //etc ... } 
3
19 июля '16 в 13:18 2016-07-19 13:18 atsakymas pateikiamas molbalga liepos 19, 16, 13:18 2016-07-19 13:18

Pasirinkdami savybes, galite padaryti kažką bendresnio, bet konkrečiai nurodykite tipą, kurį pasirinkote, jūsų atveju „Užsakymas“:

parašykite savo funkciją kaip bendrą:

 public List<Order> GetOrderList<T>(IEnumerable<Order> orders, Func<Order, T> propertySelector) { return (from order in orders orderby propertySelector(order) select order).ToList(); } 

tada naudokite jį taip:

 var ordersOrderedByDate = GetOrderList(orders, x => x.OrderDate); 

Jūs galite būti dar bendresnis ir nustatyti atvirą tipą, kurį norite užsisakyti:

 public List<T> OrderBy<T,P>(IEnumerable<T> collection, Func<T,P> propertySelector) { return (from item in collection orderby propertySelector(item) select item).ToList(); } 

ir naudokite jį taip pat:

 var ordersOrderedByDate = OrderBy(orders, x => x.OrderDate); 

Koks kvailas nereikalingas sudėtingas būdas padaryti LINQ „OrderBy“ stilių, tačiau jis gali suprasti, kaip tai galima įgyvendinti bendrai.

3
02 апр. Danny Mor atsakymas, pateiktas balandžio 02 d 2015-04-02 11:01 '15 at 11:01 AM 2015-04-02 11:01
 //Get data from database, then sort list by staff name: List<StaffMember> staffList = staffHandler.GetStaffMembers(); var sortedList = from staffmember in staffList orderby staffmember.Name ascending select staffmember; 
3
24 нояб. Atsakymą pateikė Waqas Ahmed lapkričio 24 d. 2011-11-24 00:42 '11 prie 0:42 2011-11-24 00:42

Naudojant LINQ

 objListOrder = GetOrderList() .OrderBy(o => o.OrderDate) .ToList(); objListOrder = GetOrderList() .OrderBy(o => o.OrderId) .ToList(); 
3
22 июля '10 в 16:16 2010-07-22 16:16 Atsakymą pateikė Daniel A. White, liepos 22 d., 10 val., 16:16, 2010-07-22 16:16

Nė vienas iš pirmiau pateiktų atsakymų man nebuvo pakankamai bendras, todėl aš tai padariau:

 var someUserInputStringValue = "propertyNameOfObject ie 'Quantity' or 'Date'"; var SortedData = DataToBeSorted .OrderBy(m => m.GetType() .GetProperties() .First(n => n.Name == someUserInputStringValue) .GetValue(m, null)) .ToList(); 

Saugokitės didelių duomenų rinkinių. Tai paprastas kodas, tačiau jis gali sukelti problemų, jei kolekcija yra didžiulė, o rinkimo objekto tipas turi daug laukų. Paleidimo laikas - NxM, kur:

N = # rinkinyje

M = # objekto ypatybės

2
22 авг. atsakymą pateikė itcropper 22 rug . 2016-08-22 21:45 '16 at 21:45 2016-08-22 21:45
 var obj = db.Items.Where... var orderBYItemId = obj.OrderByDescending(c => Convert.ToInt32(c.ID)); 
2
31 мая '17 в 11:26 2017-05-31 11:26 atsakymą pateikė Jevgenij Kononov gegužės 17 d. 17 val. 11:26

Naudokite „LiNQ OrderBy“

 List<Order> objListOrder=new List<Order> (); objListOrder=GetOrderList().OrderBy(o=>o.orderid).ToList(); 
1
22 июля '10 в 16:16 2010-07-22 16:16 atsakymą pateikė Pranay Rana , liepos 22 d. , 10:16, 2010-07-22 16:16

Remiantis „ GenericTypeTea“ . Palyginimas:
mes galime gauti daugiau lankstumo pridedant rūšiavimo vėliavas:

 public class MyOrderingClass : IComparer<Order> { public int Compare(Order x, Order y) { int compareDate = x.Date.CompareTo(y.Date); if (compareDate == 0) { int compareOrderId = x.OrderID.CompareTo(y.OrderID); if (OrderIdDescending) { compareOrderId = -compareOrderId; } return compareOrderId; } if (DateDescending) { compareDate = -compareDate; } return compareDate; } public bool DateDescending { get; set; } public bool OrderIdDescending { get; set; } } 

Tokiu atveju turite aiškiai nurodyti „ MyOrderingClass“ (o ne „ IComparer“ )
nustatyti savo rūšiavimo savybes:

 MyOrderingClass comparer = new MyOrderingClass(); comparer.DateDescending = ...; comparer.OrderIdDescending = ...; orderList.Sort(comparer); 
1
06 янв. Atsakymą pateikė Jack Griffin, sausio 06 2015-01-06 16:47 '15 - 16:47 2015-01-06 16:47

Jei norite naudoti „ CompareTo , reikia <Kažkas, kuris dirba su nulinės vertės tipais, Value .

objListOrder.Sort((x, y) => x.YourNullableType.Value.CompareTo(y.YourNullableType.Value));

0
19 янв. Atsakymas duotas Jude Sausio 19 d 2017-01-19 18:35 '17 at 6:35 2017-01-19 18:35

Kalbant apie našumą, geriausia naudoti surūšiuotą sąrašą, kad duomenys būtų surūšiuoti, nes jie pridedami prie rezultato. Kiti metodai reikalauja bent vieno papildomo iteracijos duomenų atžvilgiu, o dauguma jų sukuria duomenų kopiją, todėl bus paveiktas ne tik našumas, bet ir atminties naudojimas. Tai gali būti ne keleto šimtų elementų problema, bet ji bus su tūkstančiais, ypač tose paslaugose, kuriose vienu metu galima surūšiuoti kelias lygiagrečias užklausas. Pažvelkite į System.Collections.Generic vardų sritį ir pasirinkite klasę su rūšiavimu vietoj sąrašo.

Ir venkite bendrų diegimų, jei įmanoma, naudojant atspindį, gali kilti ir problemų.

0
31 июля '14 в 14:53 2014-07-31 14:53 atsakymą pateikė vartotojo3285954 liepos 31 d. 14:53 2014-07-31 14:53

Žr. Kitus klausimus apie žymių arba Užduoti klausimą