C # में एक IList छाँटना


86

इसलिए मुझे आज एक दिलचस्प समस्या सामने आई। हमारे पास एक WCF वेब सेवा है जो एक IList लौटाती है। वास्तव में एक बड़ी बात नहीं है जब तक कि मैं इसे सुलझाना नहीं चाहता था।

बाहर निकलता है IList इंटरफ़ेस में निर्मित एक सॉर्ट विधि नहीं है।

मैंने ArrayList.Adapter(list).Sort(new MyComparer())समस्या को हल करने के लिए विधि का उपयोग कर समाप्त किया, लेकिन यह मुझे थोड़ा "घेटो" लग रहा था।

मैं एक विस्तार विधि लिखने के साथ तैयार किया गया, वह भी आईलिस्ट से विरासत में मिला और अपने खुद के क्रमबद्ध () पद्धति को लागू करने के साथ-साथ एक सूची में भी डाला गया लेकिन इनमें से कोई भी अति सुंदर नहीं लगा।

तो मेरा सवाल यह है कि क्या किसी के पास इलिस्ट को हल करने का एक सुंदर समाधान है


आप पहले स्थान पर आईएलस्ट क्यों लौटाएंगे? एक WCF सेवा से?
डेहोहोहोन

जवाबों:


54

आपके लिए सॉर्ट करने के लिए LINQ ऑब्जेक्ट्स का उपयोग करने के बारे में कैसे?

कहो कि आपके पास एक IList<Car>कार है, और कार में एक Engineसंपत्ति थी, मेरा मानना ​​है कि आप निम्नानुसार छाँट सकते हैं:

from c in list
orderby c.Engine
select c;

संपादित करें: आपको यहां उत्तर प्राप्त करने के लिए त्वरित होने की आवश्यकता है। जैसा कि मैंने अन्य उत्तरों के लिए थोड़ा अलग वाक्यविन्यास प्रस्तुत किया है, मैं अपना उत्तर छोड़ दूंगा - हालांकि, प्रस्तुत किए गए अन्य उत्तर समान रूप से मान्य हैं।


3
यह एक नई गणना करेगा, जो कुछ परिदृश्यों में वांछनीय नहीं हो सकता है। आप मेरे ज्ञान में ArrayList.Adcape पद्धति का उपयोग करके इंटरफ़ेस के माध्यम से एक IList <T> इन-प्लेस को सॉर्ट नहीं कर सकते।
तनवीर बदर

67

आप LINQ का उपयोग कर सकते हैं:

using System.Linq;

IList<Foo> list = new List<Foo>();
IEnumerable<Foo> sortedEnum = list.OrderBy(f=>f.Bar);
IList<Foo> sortedList = sortedEnum.ToList();

61

इस सवाल ने मुझे ब्लॉग पोस्ट लिखने के लिए प्रेरित किया: http://blog.velir.com/index.php/2011/02/17/ilistt-sorting-a-better-way/

मुझे लगता है कि, आदर्श रूप से, .NET फ्रेमवर्क में एक स्थिर सॉर्टिंग विधि शामिल होगी जो IList <T> को स्वीकार करती है, लेकिन अगली सबसे अच्छी बात यह है कि आप अपनी एक्सटेंशन विधि बनाएं। कुछ तरीकों को बनाना बहुत कठिन नहीं है जो आपको एक सूची <टी> के रूप में एक IList <T> को सॉर्ट करने की अनुमति देगा। एक बोनस के रूप में आप एक ही तकनीक का उपयोग करके LINQ ऑर्डरबी एक्सटेंशन विधि को अधिभारित कर सकते हैं, ताकि चाहे आप 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));
    }

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

इन एक्सटेंशनों के साथ, अपने 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/


1
सही दृष्टिकोण वास्तव में एक ISortableList<T>इंटरफ़ेस की पेशकश करने के लिए होता (कुछ विशेष तुलनित्र का उपयोग करके सूची के एक हिस्से को सॉर्ट करने के लिए), इसे List<T>लागू किया है, और एक स्थिर विधि है जो किसी भी तरह IList<T>से जाँच कर सकती है कि क्या इसे लागू किया गया है ISortableList<T>और यदि नहीं, तो इसे एक सरणी में कॉपी करना, उस को सॉर्ट करना, साफ़ करना IList<T>और आइटम को फिर से जोड़ना।
सुपरकट

4
अद्भुत जवाब! हालाँकि, सावधानी का एक शब्द: यह दृष्टिकोण मानता है कि IList<T> listइसे गैर-जेनेरिक IListइंटरफ़ेस में डाला जा सकता है। यदि आप IList<T>इंटरफ़ेस को लागू करने वाले अपने स्वयं के वर्ग को कोड करते हैं , तो सुनिश्चित करें कि आप गैर-जेनेरिक IListइंटरफ़ेस को भी लागू करते हैं , या कोड एक क्लास कास्ट अपवाद के साथ विफल हो जाएगा।
sstan

1
@ सुपरकैट: वह ISortableList<T>पेशकश जो पहले से ही नहीं है IList<T>? या, अलग तरीके से पूछा गया है कि IList<T>आपके कल्पना स्थैतिक विधि द्वारा आइटम को फिर से जोड़ने के बिना इन-प्लेस को क्यों सॉर्ट किया जा सकता है?
या मैपर

@ORMapper: यदि कोई सूची किसी सरणी को बैकिंग स्टोर (सामान्य, लेकिन आवश्यक नहीं) के रूप में उपयोग करती है, तो एक प्रकार की दिनचर्या जो सरणी तत्वों को सीधे एक्सेस करती है, वह एक से अधिक तेज हो सकती है, जिसे IList<T>प्रत्येक तत्व तक पहुंचने के लिए इंटरफ़ेस से गुजरना पड़ता है। गति का अंतर पर्याप्त रूप से महान है कि कई मामलों में किसी सूची को किसी सरणी में कॉपी करने, सरणी को सॉर्ट करने और सूची को कॉपी करने के लिए तेजी से हो सकता है, जगह में सूची को क्रमबद्ध करने की कोशिश करने की तुलना में।
सुपरकाट

1
ComparisonComparerवर्ग आवश्यक नहीं है। आप Comparer<T>.Create(comparison)इसके बजाय मानक स्थैतिक विधि का उपयोग कर सकते हैं ।
लाइनपोगल

9

आप ऐसा कुछ करने जा रहे हैं जो मुझे लगता है कि (इसे और अधिक ठोस प्रकार में परिवर्तित करें)।

हो सकता है कि इसे ArrayList के बजाय T की सूची में ले जाएं, ताकि आपको टाइप सुरक्षा और अधिक विकल्प मिलें कि आप तुलना करने वाले को कैसे लागू करते हैं।


4

@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>)

निम्न वर्ग इंटरफ़ेस के List<T>.Sort()लिए सभी 4 हस्ताक्षर लागू करता 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इंटरफ़ेस को लागू नहीं करती है।


2
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));**

1

मूल सूत्र में वर्णित सटीक समस्या के समाधान की तलाश करते हुए मुझे यह धागा मिला। हालाँकि किसी भी उत्तर ने मेरी स्थिति को पूरी तरह से पूरा नहीं किया है। ब्रॉडी का जवाब बहुत करीब था। यहां मेरी स्थिति और समाधान है जो मुझे मिला।

मेरे पास NHibernate द्वारा दिए गए एक ही प्रकार के दो ILists हैं और दो IList एक में उभरे हैं, इसलिए छंटाई की आवश्यकता है।

जैसे ब्रॉडी ने कहा कि मैंने ऑब्जेक्ट (ReportFormat) पर एक ICompare लागू किया, जो मेरे 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 की तरह ही किया जा सकता है।


1

संपत्ति के नामों के आधार पर इस पद्धति की सूची को छाँटने के लिए उपयोगी ग्रिड। उदाहरण के रूप में।

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

0

यहां मजबूत टाइपिंग का उपयोग करके एक उदाहरण दिया गया है। यह निश्चित रूप से सबसे अच्छा तरीका है, हालांकि यकीन नहीं है।

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

कास्ट फ़ंक्शन एक्सटेंशन पद्धति का केवल एक पुन: कार्यान्वयन है जो 3.5 के साथ आता है जो सामान्य स्थैतिक विधि के रूप में लिखा जाता है। यह दुर्भाग्य से काफी बदसूरत और क्रिया है।


0

VS2008 में, जब मैं सेवा संदर्भ पर क्लिक करता हूं और "कॉन्फ़िगर सेवा संदर्भ" का चयन करता हूं, तो यह चुनने का विकल्प होता है कि ग्राहक डी-क्रमबद्ध सूचियों को सेवा से कैसे लौटाए।

विशेष रूप से, मैं System.Array, System.Collections.ArrayList और System.Collections.Generic.List के बीच चयन कर सकता हूं।


0
using System.Linq;

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

यह सुंदर है! यहूदी बस्ती।


0

इस पर एक अच्छा पोस्ट मिला और सोचा कि मैं साझा करूँगा। यहां इसकी जांच कीजिए

मूल रूप से।

आप निम्न वर्ग और IComparer Classes बना सकते हैं

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

फिर यदि आपके पास एक आईएलस्ट है, तो आप इसे इस तरह से सॉर्ट कर सकते हैं।

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

लेकिन अधिक जानकारी के लिए इस साइट को चेकआउट करें ... यहां देखें


0

क्या यह एक वैध समाधान है?

        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 फिर से A B C


1
मान्य अगर यह वास्तव में एक सूची है <T>। कुछ मामलों में, आपके पास IList <T> को लागू करने के अन्य प्रकार हैं (उदाहरण के लिए, एक सादा सरणी) जहां डाउनकास्ट काम नहीं करेगा। बहुत बुरा है कि क्रमबद्ध () विधि IList <T> के लिए एक विस्तार विधि नहीं है।
साइगॉन

0

यदि आप मुझसे पूछें तो यह अधिक सरल लगता है। यह पूरी तरह से मेरे लिए काम करता है।

आप कास्ट का उपयोग कर सकते हैं () इसे IList में बदलने के लिए फिर ऑर्डरबी () का उपयोग करें

    var ordered = theIList.Cast<T>().OrderBy(e => e);

जहां टी टाइप है। Model.Employee या Plugin.ContactService.Saring.Contact

फिर आप लूप और उसके DONE के लिए उपयोग कर सकते हैं।

  ObservableCollection<Plugin.ContactService.Shared.Contact> ContactItems= new ObservableCollection<Contact>();

    foreach (var item in ordered)
    {
       ContactItems.Add(item);
    }

-1

अपने या किसी अन्य सामान्य संग्रह IListमें कनवर्ट करें List<T>और फिर आप System.Linqनाम स्थान का उपयोग करके इसे आसानी से क्वेरी / सॉर्ट कर सकते हैं (यह एक्सटेंशन विधियों के गुच्छा की आपूर्ति करेगा)


9
IList<T>आवेदन IEnumerable<T>और इसलिए Linq संचालन का उपयोग करने के लिए परिवर्तित करने की आवश्यकता नहीं है।
स्टीव गाइडी जूल 13'10
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.