c# - كيفية فرز قائمة<T> بواسطة خاصية في الكائن



generics list (13)

// فرز عام تمامًا للاستخدام مع عرض الشبكة

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);
    }

https://code.i-harness.com

لدي فئة تسمى " Order الذي يحتوي على خصائص مثل OrderId و OrderDate و Quantity و Total . لدي قائمة من هذا الفصل الدراسي:

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

الآن أريد فرز القائمة بناءً على خاصية واحدة من كائن Order ، على سبيل المثال ، أحتاج إلى ترتيبها حسب تاريخ الطلب أو معرف الطلب.

كيف يمكنني القيام بذلك في C #؟


أسهل طريقة يمكنني التفكير فيها هي استخدام Linq:

List<Order> SortedList = objListOrder.OrderBy(o=>o.OrderDate).ToList();

إذا كنت بحاجة إلى فرز القائمة في المكان ، فيمكنك استخدام طريقة Sort ، مع تمرير Comparison<T> مفوض:

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

إذا كنت تفضل إنشاء تسلسل جديد وفريد ​​بدلاً من الفرز في المكان ، فيمكنك استخدام أسلوب OrderBy الخاص بـ LINQ ، كما هو مذكور في الإجابات الأخرى.


إذا كنت تريد شيء من هذا القبيل

ORDER BY OrderDate, OrderId

ثم حاول مثل متابعة.

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

القيام بذلك دون Linq كما قلت:

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;
    }
}

ثم اتصل فقط. فرز () على قائمة الطلبات الخاصة بك


باستخدام LINQ

objListOrder = GetOrderList()
                   .OrderBy(o => o.OrderDate)
                   .ToList();

objListOrder = GetOrderList()
                   .OrderBy(o => o.OrderId)
                   .ToList();

تحسن نسخة روجر.

المشكلة مع GetDynamicSortProperty هي أن فقط الحصول على أسماء الممتلكات ولكن ماذا يحدث إذا كان في GridView نستخدم NavigationProperties؟ سوف يرسل استثناء ، لأنه يجد فارغة.

مثال:

سيتحطم "Employee.Company.Name؛" ... لأنه يسمح فقط بـ "الاسم" كمعلمة للحصول على قيمتها.

فيما يلي نسخة محسنة تسمح لنا بالفرز حسب خصائص التنقل.

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;
        }


    } 

فيما يلي أسلوب ملحق LINQ عام لا يقوم بإنشاء نسخة إضافية من القائمة:

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)));
}

لتستخدمها:

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

قمت مؤخراً ببناء هذه الوحدة الإضافية التي تقبل ICompare<U> ، بحيث يمكنك تخصيص المقارنة. جاء هذا في متناول اليدين عندما كنت بحاجة إلى القيام بفرز سلسلة الطبيعية:

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)));
}

لم يكن أي من الإجابات المذكورة أعلاه عامًا بما فيه الكفاية بالنسبة لي ، لذا فقد صنعت هذا:

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

حذرا على مجموعات البيانات الضخمة رغم ذلك. إنه رمز سهل ولكنه قد يسبب لك مشكلة إذا كانت المجموعة ضخمة ويحتوي نوع كائن المجموعة على عدد كبير من الحقول. وقت التشغيل هو NxM حيث:

N = # من العناصر في المجموعة

م = # خصائص داخل كائن


من فضلكم دعوني أكمل الإجابة بـLukeH مع بعض نماذج التعليمة البرمجية ، حيث إنني قمت باختبارها وأعتقد أنها قد تكون مفيدة لبعض:

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 ...
}

يمكنك القيام بشيء أكثر عمومية حول اختيار الخصائص مع تحديد النوع الذي تختاره من ، في حالتك 'أمر':

اكتب وظيفتك كعامل عام:

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

ثم استخدمها على هذا النحو:

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

يمكنك أن تكون أكثر عمومية وتحدد نوعًا مفتوحًا لما تريد أن تطلبه:

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

واستخدامها بنفس الطريقة:

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

وهي طريقة معقدة غبية لا لزوم لها للقيام بأسلوب LINQ "OrderBy" ، ولكنها قد تعطيك فكرة عن كيفية تنفيذها بطريقة عامة


حل كائن كلاسيكي

أولا يجب أن أكون جياشة لذهول LINQ .... الآن أن لدينا هذا الخروج من الطريق

وهناك اختلاف على الإجابة JimmyHoffa. مع علم الوراثة تصبح المعلمة CompareTo آمنة.

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(); 

هذه الفرز الافتراضية قابلة لإعادة الاستخدام بالطبع. هذا ليس لدى كل عميل إلى إعادة كتابة منطق الفرز. تبديل "1" و "-1" (أو عوامل التشغيل المنطقية ، اختيارك) عكس ترتيب الفرز.


var obj = db.Items.Where...

var orderBYItemId = obj.OrderByDescending(c => Convert.ToInt32(c.ID));




sorting