سؤال

لذلك واجهت مشكلة مثيرة للاهتمام اليوم.لدينا خدمة ويب 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;

يحرر:عليك أن تكون سريعًا للحصول على الإجابات هنا.نظرًا لأنني قدمت صيغة مختلفة قليلاً عن الإجابات الأخرى، فسوف أترك إجابتي - ومع ذلك، فإن الإجابات الأخرى المقدمة صالحة بنفس القدر.

نصائح أخرى

يمكنك استخدام لينك:

using System.Linq;

IList<Foo> list = new List<Foo>();
IEnumerable<Foo> sortedEnum = list.OrderBy(f=>f.Bar);
IList<Foo> sortedList = sortedEnum.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/

سيتعين عليك القيام بشيء كهذا على ما أعتقد (تحويله إلى نوع أكثر واقعية).

ربما يمكنك إدراجها في قائمة T بدلاً من ArrayList، بحيث تحصل على أمان الكتابة والمزيد من الخيارات لكيفية تنفيذ المقارنة.

الإجابة المقبولة منDavidMills جيدة جدًا، ولكن أعتقد أنه يمكن تحسينها.أولاً، ليست هناك حاجة لتحديد ComparisonComparer<T> فئة عندما يتضمن الإطار بالفعل طريقة ثابتة Comparer<T>.Create(Comparison<T>).يمكن استخدام هذه الطريقة لإنشاء IComparison على الطاير.

كما أنه يلقي IList<T> ل IList والتي لديها القدرة على أن تكون خطيرة.وفي أغلب الحالات التي رأيتها، List<T> الذي ينفذ IList يتم استخدامه خلف الكواليس للتنفيذ IList<T>, ، ولكن هذا غير مضمون ويمكن أن يؤدي إلى كود هش.

وأخيرا، الزائد List<T>.Sort() تحتوي الطريقة على 4 توقيعات وتم تنفيذ 2 منها فقط.

  1. List<T>.Sort()
  2. List<T>.Sort(Comparison<T>)
  3. List<T>.Sort(IComparer<T>)
  4. 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 واجهه المستخدم.

لقد وجدت هذا الموضوع بينما كنت أبحث عن حل للمشكلة المحددة الموضحة في المشاركة الأصلية.ومع ذلك، لم تلبي أي من الإجابات وضعي بالكامل.كانت إجابة برودي قريبة جدًا.هذا هو وضعي والحل الذي وجدته له.

لدي قائمتي 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 الأصلي.

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

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

تحويل الخاص بك IList داخل List<T> أو بعض المجموعات العامة الأخرى ومن ثم يمكنك بسهولة الاستعلام/الفرز باستخدامها System.Linq مساحة الاسم (ستوفر مجموعة من طرق الامتداد)

إليك مثال باستخدام الكتابة الأقوى.لست متأكدًا مما إذا كانت هذه هي الطريقة الأفضل بالضرورة.

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

using System.Linq;

var yourList = SomeDAO.GetRandomThings();
yourList.ToList().Sort( (thing, randomThing) => thing.CompareThisProperty.CompareTo( randomThing.CompareThisProperty ) );

هذا جميل! الغيتو.

لقد وجدت منشورًا جيدًا حول هذا واعتقدت أنني سأشاركه. تحقق من ذلك هنا

أساسًا.

يمكنك إنشاء الفئة التالية وفئات 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());

ولكن تحقق من هذا الموقع لمزيد من المعلومات ... تحقق من ذلك هنا

هل هذا حل صالح؟

        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 مرة أخرى أ ب ج

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top