मैं एक अवलोकन योग्य संग्रह कैसे छाँट सकता हूँ?


97

मेरे पास निम्न वर्ग है:

[DataContract]
public class Pair<TKey, TValue> : INotifyPropertyChanged, IDisposable
{
    public Pair(TKey key, TValue value)
    {
        Key = key;
        Value = value;
    }

    #region Properties
    [DataMember]
    public TKey Key
    {
        get
        { return m_key; }
        set
        {
            m_key = value;
            OnPropertyChanged("Key");
        }
    }
    [DataMember]
    public TValue Value
    {
        get { return m_value; }
        set
        {
            m_value = value;
            OnPropertyChanged("Value");
        }
    }
    #endregion

    #region Fields
    private TKey m_key;
    private TValue m_value;
    #endregion

    #region INotifyPropertyChanged Members

    public event PropertyChangedEventHandler PropertyChanged;

    protected void OnPropertyChanged(string name)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(name));
        }
    }

    #endregion

    #region IDisposable Members

    public void Dispose()
    { }

    #endregion
}

जो मैंने एक वेधशाला में रखा है:

ObservableCollection<Pair<ushort, string>> my_collection = 
    new ObservableCollection<Pair<ushort, string>>();

my_collection.Add(new Pair(7, "aaa"));
my_collection.Add(new Pair(3, "xey"));
my_collection.Add(new Pair(6, "fty"));

प्रश्न: मैं इसे कुंजी द्वारा कैसे हल कर सकता हूं?


क्या आप कक्षा के भीतर एक छँटाई कार्यान्वयन की तलाश कर रहे हैं या सिर्फ किसी भी प्रकार की छँटाई करेंगे?
okw

समझ में नहीं आ रहा है कि कैसे समझें। मूल रूप से मैं बस इसे क्रमबद्ध करना चाहता हूं, संग्रह बहुत बड़ा नहीं होने वाला है (20 आइटम अधिकतम) इसलिए कुछ भी करेगा (सबसे अधिक संभावना है)
Maciek

WPF समाधान के लिए इसे देखें देखें stackoverflow.com/questions/1945461/…
Gayot Fow

इस पृष्ठ के उत्तरों को देखें: किसी टूटी हुई एपीआई के बहुत स्पष्ट संकेत जब यह कुछ महत्वपूर्ण और बुनियादी कार्यक्षमता के लिए 22+ उत्तर लेता है।
गेरी

जवाबों:


19

एक ऑब्जर्वेबल को सॉर्ट करना और एक ही ऑब्जेक्ट को छांटना एक एक्सटेंशन विधि का उपयोग करके किया जा सकता है। बड़े संग्रह के लिए, संग्रह की बदली सूचनाओं की संख्या देखें।

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

public static void Sort<T>(this ObservableCollection<T> collection)
        where T : IComparable<T>, IEquatable<T>
    {
        List<T> sorted = collection.OrderBy(x => x).ToList();

        int ptr = 0;
        while (ptr < sorted.Count - 1)
        {
            if (!collection[ptr].Equals(sorted[ptr]))
            {
                int idx = search(collection, ptr+1, sorted[ptr]);
                collection.Move(idx, ptr);
            }
            
            ptr++;
        }
    }

    public static int search<T>(ObservableCollection<T> collection, int startIndex, T other)
            {
                for (int i = startIndex; i < collection.Count; i++)
                {
                    if (other.Equals(collection[i]))
                        return i;
                }
    
                return -1; // decide how to handle error case
            }

उपयोग: एक पर्यवेक्षक के साथ नमूना (इसे सरल रखने के लिए एक व्यक्ति वर्ग का उपयोग किया गया)

    public class Person:IComparable<Person>,IEquatable<Person>
            { 
                public string Name { get; set; }
                public int Age { get; set; }
    
                public int CompareTo(Person other)
                {
                    if (this.Age == other.Age) return 0;
                    return this.Age.CompareTo(other.Age);
                }
    
                public override string ToString()
                {
                    return Name + " aged " + Age;
                }
    
                public bool Equals(Person other)
                {
                    if (this.Name.Equals(other.Name) && this.Age.Equals(other.Age)) return true;
                    return false;
                }
            }
    
          static void Main(string[] args)
            {
                Console.WriteLine("adding items...");
                var observable = new ObservableCollection<Person>()
                {
                    new Person {Name = "Katy", Age = 51},
                    new Person {Name = "Jack", Age = 12},
                    new Person {Name = "Bob", Age = 13},
                    new Person {Name = "Alice", Age = 39},
                    new Person {Name = "John", Age = 14},
                    new Person {Name = "Mary", Age = 41},
                    new Person {Name = "Jane", Age = 20},
                    new Person {Name = "Jim", Age = 39},
                    new Person {Name = "Sue", Age = 5},
                    new Person {Name = "Kim", Age = 19}
                };
    
                //what do observers see?
            
    
observable.CollectionChanged += (sender, e) =>
        {
            Console.WriteLine(
                e.OldItems[0] + " move from " + e.OldStartingIndex + " to " + e.NewStartingIndex);
            int i = 0;
            foreach (var person in sender as ObservableCollection<Person>)
            {
                if (i == e.NewStartingIndex)
                {
                    Console.Write("(" + (person as Person).Age + "),");
                }
                else
                {
                    Console.Write((person as Person).Age + ",");
                }
                
                i++;
            }

            Console.WriteLine();
        };

प्रगति को छाँटने का विवरण यह दिखाता है कि संग्रह कैसे प्रस्तुत किया गया है:

Sue aged 5 move from 8 to 0
(5),51,12,13,39,14,41,20,39,19,
Jack aged 12 move from 2 to 1
5,(12),51,13,39,14,41,20,39,19,
Bob aged 13 move from 3 to 2
5,12,(13),51,39,14,41,20,39,19,
John aged 14 move from 5 to 3
5,12,13,(14),51,39,41,20,39,19,
Kim aged 19 move from 9 to 4
5,12,13,14,(19),51,39,41,20,39,
Jane aged 20 move from 8 to 5
5,12,13,14,19,(20),51,39,41,39,
Alice aged 39 move from 7 to 6
5,12,13,14,19,20,(39),51,41,39,
Jim aged 39 move from 9 to 7
5,12,13,14,19,20,39,(39),51,41,
Mary aged 41 move from 9 to 8
5,12,13,14,19,20,39,39,(41),51,

व्यक्ति वर्ग IComparable और IEquatable दोनों को लागू करता है, बाद में संग्रह में परिवर्तन को कम करने के लिए उपयोग किया जाता है ताकि उठाए गए परिवर्तन सूचनाओं की संख्या कम हो सके।

  • EDIT नई प्रति बनाए बिना एक ही संग्रह बनाता है *

एक वेधशाला का चयन करने के लिए, कॉल .ToObservableCollection पर * SortedOC * जैसे [इस कार्यान्वयन] [1] का उपयोग कर।

**** मूल उत्तर - यह एक नया संग्रह बनाता है **** आप रेखांकन का उपयोग चित्र के नीचे चित्र विधि के रूप में कर सकते हैं। एक त्वरित कोड स्निपेट: उत्पादन करता है

3: xey 6: fty 7: aaa

वैकल्पिक रूप से आप संग्रह पर ही एक्सटेंशन विधि का उपयोग कर सकते हैं

var sortedOC = _collection.OrderBy(i => i.Key);

private void doSort()
{
    ObservableCollection<Pair<ushort, string>> _collection = 
        new ObservableCollection<Pair<ushort, string>>();

    _collection.Add(new Pair<ushort,string>(7,"aaa"));
    _collection.Add(new Pair<ushort, string>(3, "xey"));
    _collection.Add(new Pair<ushort, string>(6, "fty"));

    var sortedOC = from item in _collection
                   orderby item.Key
                   select item;

    foreach (var i in sortedOC)
    {
        Debug.WriteLine(i);
    }

}

public class Pair<TKey, TValue>
{
    private TKey _key;

    public TKey Key
    {
        get { return _key; }
        set { _key = value; }
    }
    private TValue _value;

    public TValue Value
    {
        get { return _value; }
        set { _value = value; }
    }
    
    public Pair(TKey key, TValue value)
    {
        _key = key;
        _value = value;

    }

    public override string ToString()
    {
        return this.Key + ":" + this.Value;
    }
}

यह मिला और इसे सबसे अधिक उपयोगी बताया। क्या यह LINQ है जो सॉर्ट किए गए var को बनाता है?
जेसन94

9
इस उत्तर का प्रशंसक नहीं है क्योंकि यह आपको एक छांटे गए अवलोकन योग्य नहीं देता है।
xr280xr

63
-1 चूंकि यह सॉर्ट नहीं करता है ObservableCollection , लेकिन इसके बजाय एक नया संग्रह बनाता है।
कोस

2
अपडेट किया गया कोड काम करेगा, लेकिन O (n ^ 2) समय की जटिलता है। इसके BinarySearchबजाय का उपयोग करके O (n * log (n)) में सुधार किया जा सकता है IndexOf
विलियम मॉरिसन

2
उत्कृष्ट समाधान! ऑब्जर्वेबलकोलेक्शन <टी> से विरासत में प्राप्त लोगों के लिए, RemoveAt और इन्सर्ट विधियों का उपयोग करने के बजाय संरक्षित MoveItem () विधि का उपयोग करना संभव है। यह भी देखें: referencesource.microsoft.com/#system/compmod/system/...
हरमन Cordes

84

इस सरल विस्तार ने मेरे लिए खूबसूरती से काम किया। मुझे बस यह सुनिश्चित करना MyObjectथा कि वह था IComparable। जब सॉर्ट विधि को अवलोकन योग्य संग्रह पर कहा जाता है MyObjects, तो उस CompareToविधि MyObjectको कहा जाता है, जिसे मेरा लॉजिकल सॉर्ट विधि कहा जाता है। हालांकि इसमें यहां पोस्ट किए गए बाकी के सभी घंटियाँ और सीटी नहीं हैं, यह बिल्कुल वही है जिसकी मुझे ज़रूरत थी।

static class Extensions
{
    public static void Sort<T>(this ObservableCollection<T> collection) where T : IComparable
    {
        List<T> sorted = collection.OrderBy(x => x).ToList();
        for (int i = 0; i < sorted.Count(); i++)
            collection.Move(collection.IndexOf(sorted[i]), i);
    }
}

public class MyObject: IComparable
{
    public int CompareTo(object o)
    {
        MyObject a = this;
        MyObject b = (MyObject)o;
        return Utils.LogicalStringCompare(a.Title, b.Title);
    }

    public string Title;

}
  .
  .
  .
myCollection = new ObservableCollection<MyObject>();
//add stuff to collection
myCollection.Sort();

7
इसका उत्तर होना चाहिए
थंबमुनकेज

1
ऊपर मेरे उत्तर को अपडेट किया गया क्योंकि यह स्वीकार किया गया था और इस उत्तर पर प्रदर्शन सुधार को संबोधित करता है जो संग्रह में सब कुछ के लिए सूचनाएं बदल देता है
एंड्रयू

3
बहुत बढ़िया जवाब। किसी भी कारण के return Utils.LogicalStringCompare(a.Title, b.Title);बजाय आप का उपयोग क्यों return string.Compare(a.Title, b.Title);? @ नील
जो

2
@ जो, मुझे मानक स्ट्रिंग तुलना के बजाय तार्किक तुलना करने की आवश्यकता थी, यही कारण है कि मुझे पहले स्थान पर विस्तार लिखने की आवश्यकता थी। तार्किक स्ट्रिंग स्ट्रिंग्स में संख्याओं की तुलना ठीक से करती है, न कि उन्हें स्ट्रिंग्स (1, 2, 20, 1000 के बजाय 1, 1000, 2, 20, इत्यादि) के
आदेश के रूप में

4
यह बिल्कुल जाने का रास्ता है। मैंने इसे स्वयं विस्तारित करने का एक उत्तर जोड़ा, जिससे आपको IComparable का उपयोग करने के बजाय एक KeySelector में पास करने की अनुमति मिलती है, जैसे LINQ आमतौर पर करता है।
जोन्सोपोलिस

39

मुझे एक प्रासंगिक ब्लॉग प्रविष्टि मिली जो यहां के लोगों की तुलना में बेहतर उत्तर प्रदान करती है:

http://kiwigis.blogspot.com/2010/03/how-to-sort-obversablecollection.html

अपडेट करें

ObservableSortedList कि टिप्पणी में बाहर @romkyns अंक स्वतः सॉर्ट क्रम को बनाए रखता है।

इम्प्लीमेन्ट्स एक अवलोकनीय संग्रह है जो क्रमबद्ध क्रम में अपनी वस्तुओं को बनाए रखता है। विशेष रूप से, आइटम गुणों में परिवर्तन, जिसके परिणामस्वरूप क्रम परिवर्तन सही तरीके से संभाला जाता है।

हालांकि टिप्पणी भी ध्यान दें

इसमें शामिल इंटरफ़ेस की तुलनात्मक जटिलता और इसके अपेक्षाकृत खराब प्रलेखन ( https://stackoverflow.com/a/5883947/33080 देखें ) के कारण छोटी हो सकती है ।


2
वास्तव में, यह ब्लॉग अधिक उपयोगी है। हालाँकि, मुझे अभी तक एक अवलोकन योग्य संग्रह होने के सवाल का एक सभ्य जवाब मिल गया है जो आइटमों को जोड़ने और हटाए जाने के रूप में इसकी छंटाई को बनाए रखता है। मुझे लगता है कि मैं अपना खुद का लिखने जा रहा हूं।
स्टीफन ने

@Steve आप कोशिश कर सकते हैं यह एक
रोमन स्टार्कोव 13/12

लिंक के लिए धन्यवाद, मैं विस्तार विधि के साथ गया क्योंकि यह सबसे कठिन समाधान लग रहा था। एक आकर्षण काम करता है: D
pengibot

bw किसी ने देखा कि ब्लॉग में html फ़ाइल नाम (obversablecollection) में एक टाइपो है? : P
laishiekai

1
@romkyns का जवाब था ऑब्जर्वेबल कॉलेक्शन <T> का विस्तार करना। GridView यह तो ठीक पहचानता है। तो बस इसे छिपाने के तरीके, आप की तरह है। जब मेरे पास समय होगा मैं एक पूर्ण समाधान पोस्ट करूँगा।
वेस्टन

25

आप इस सरल विधि का उपयोग कर सकते हैं:

public static void Sort<TSource, TKey>(this Collection<TSource> source, Func<TSource, TKey> keySelector)
{
    List<TSource> sortedList = source.OrderBy(keySelector).ToList();
    source.Clear();
    foreach (var sortedItem in sortedList)
        source.Add(sortedItem);
}

आप इस तरह से हल कर सकते हैं:

_collection.Sort(i => i.Key);

अधिक विवरण: http://jaider.net/2011-05-04/sort-a-observablecollection/


4
यह ऑब्ज़र्वेबल कॉलेक्शन को साफ़ करता है, फिर सभी ऑब्जेक्ट्स को फिर से जोड़ता है - इसलिए यह ध्यान देने योग्य है कि यदि आपका यूआई संग्रह के लिए बाध्य है, तो आप एनिमेटेड बदलाव नहीं देखेंगे, जैसे आइटम जब चलते हैं
कार्लोस पी

1
मुझे यकीन नहीं है कि आपको वस्तुओं को इधर-उधर करते हुए प्रदर्शित करना है ... जैसे कि आप आम तौर पर ObservableCollectionड्रॉपडाउन के आइटम स्रोत के लिए बाध्य होते हैं और आपको संग्रह बिल्कुल दिखाई नहीं देता है। इसके अलावा क्लियर-आउट और फिल-अप का यह ऑपरेशन अल्ट्रा फास्ट है ... "धीमा" एक ऐसा सॉर्ट हो सकता है जो पहले से ही अनुकूलित है। अंत में, आप अपनी चाल विधि को लागू करने के लिए इस कोड को संशोधित कर सकते हैं, sortedlistऔर sourceशेष आसान है।
जैदर

3
यदि आप एक ड्रॉप-डाउन के लिए बाध्य हैं, तो आपको आइटमों को घूमते हुए देखने से कोई लाभ नहीं होगा, यह सच है। यदि आप एक लिस्टबॉक्स से बंधे हैं, लेकिन तब WPF या सिल्वरलाइट या विंडोज स्टोर एप जैसे फ्रेमवर्क उपयोगी दृश्य प्रतिक्रिया प्रदान करेंगे क्योंकि संग्रह में ऑब्जेक्ट्स को फिर से अनुक्रमित किया गया है।
कार्लोस पी

जबकि यह मूव एप्रोच से अधिक तेज़ है, यह कई रीसेट / इवेंट जोड़ें। उच्चतम मतदान वाला उत्तर (मूव अप्रोच) इसे कम करता है और सही ढंग से Moveघटनाओं को उठाता है, वह भी केवल वास्तव में स्थानांतरित लोगों के लिए।
नवाफल

19

WPFListCollectionView वर्ग का उपयोग करके आउट-ऑफ-द-बॉक्स को लाइव सॉर्टिंग प्रदान करता है ...

public ObservableCollection<string> MyStrings { get; set; }
private ListCollectionView _listCollectionView;
private void InitializeCollection()
{
    MyStrings = new ObservableCollection<string>();
    _listCollectionView = CollectionViewSource.GetDefaultView(MyStrings) 
              as ListCollectionView;
    if (_listCollectionView != null)
    {
        _listCollectionView.IsLiveSorting = true;
        _listCollectionView.CustomSort = new 
                CaseInsensitiveComparer(CultureInfo.InvariantCulture);
    }
}

एक बार जब यह आरंभ पूरा हो जाता है, तो ऐसा करने के लिए और कुछ नहीं होता है। एक निष्क्रिय प्रकार से अधिक लाभ यह है कि ListCollectionView डेवलपर को पारदर्शी तरीके से सभी भारी उठाने का काम करता है। नई वस्तुओं को स्वचालित रूप से उनके सही क्रम में रखा जाता है। कोई भी वर्ग जो IComparerटी से प्राप्त होता है , कस्टम सॉर्ट संपत्ति के लिए उपयुक्त है।

प्रलेखन और अन्य सुविधाओं के लिए ListCollectionView देखें ।


6
वास्तव में काम किया: डी कि इस तरह के एक सरल कार्य के लिए अन्य "अतिरंजित" समाधान की तुलना में एक बेहतर उपाय है।
मुशायरे

आपका ब्लॉग कहाँ गया?
फोगोग

"पारदर्शी" चीजों के साथ समस्या यह है कि आप यह नहीं देख सकते हैं कि यह देखने के लिए कि यह काम नहीं करता है। Microsoft के दस्तावेज़ में 100% पारदर्शी उदाहरण है, अर्थात आप इसे बिल्कुल नहीं देख सकते हैं।
पॉल मैकार्थी

15

मुझे ऊपर "रिची" ब्लॉग पर बबल सॉर्ट एक्सटेंशन विधि दृष्टिकोण पसंद आया, लेकिन मैं जरूरी नहीं कि पूरी वस्तु की तुलना करना चाहता हूं। मैं अधिक बार वस्तु की एक विशिष्ट संपत्ति पर सॉर्ट करना चाहता हूं। इसलिए मैंने इसे एक प्रमुख चयनकर्ता को स्वीकार करने के लिए संशोधित किया, जिस तरह से ऑर्डरबाय करता है इसलिए आप चुन सकते हैं कि किस संपत्ति को छाँटना है:

    public static void Sort<TSource, TKey>(this ObservableCollection<TSource> source, Func<TSource, TKey> keySelector)
    {
        if (source == null) return;

        Comparer<TKey> comparer = Comparer<TKey>.Default;

        for (int i = source.Count - 1; i >= 0; i--)
        {
            for (int j = 1; j <= i; j++)
            {
                TSource o1 = source[j - 1];
                TSource o2 = source[j];
                if (comparer.Compare(keySelector(o1), keySelector(o2)) > 0)
                {
                    source.Remove(o1);
                    source.Insert(j, o1);
                }
            }
        }
    }

जिसे आप ऑर्डरबाय कहेंगे उसी तरह से कॉल करेंगे, सिवाय इसके कि यह आपके संग्रह के मौजूदा उदाहरण को एक नए संग्रह को वापस करने के बजाय छाँटेगा:

ObservableCollection<Person> people = new ObservableCollection<Person>();
...

people.Sort(p => p.FirstName);

1
इसे पोस्ट करने के लिए धन्यवाद - जैसा कि रिची के ब्लॉग पर टिप्पणियों में बताया गया है, इस कोड में कुछ सार्थक वृद्धि हुई है; विशेष रूप से स्रोत के 'मूव' विधि का उपयोग करते हुए। मुझे लगता है कि यह स्रोत के साथ निकालें / सम्मिलित करें लाइनों की जगह लेगा। मोव (j-1, j);
कार्लोस पी

2
इस तरह एल्गोरिथ्म अनुकूल नहीं है en.wikipedia.org/wiki/Sorting_algorithm
Jaider

@ जैदर हां, यह अनुकूलित है, बस समग्र कच्ची गति के लिए नहीं।
j4242

यह कई सारे Remove / Add इवेंट्स (प्रत्येक N i विश्वास के लिए) को उठाता है .. उच्चतम मतदान वाला उत्तर इसे कम करता है और सही ढंग से Move इवेंट्स को बढ़ाता है, वह भी केवल वास्तव में स्थानांतरित किए गए लोगों के लिए। यहां कुंजी तुरंत एक जगह में सॉर्ट नहीं करना है, इसके बजाय इसे बाहरी रूप से सॉर्ट करें OrderByऔर फिर वास्तविक परिवर्तन का पता लगाने के लिए एक तुलना करें।
नवफाल

11

@ एनआईएलडब्लू का उत्तर वास्तविक इन-प्लेस सॉर्टिंग के लिए जाने का रास्ता है। मैं थोड़ा परिवर्तित समाधान जोड़ना चाहता था जिससे आप बाईपास का उपयोग कर सकें IComparable:

static class Extensions
{
    public static void Sort<TSource, TKey>(this ObservableCollection<TSource> collection, Func<TSource, TKey> keySelector)
    {
        List<TSource> sorted = collection.OrderBy(keySelector).ToList();
        for (int i = 0; i < sorted.Count(); i++)
            collection.Move(collection.IndexOf(sorted[i]), i);
    }
}

अब आप इसे किसी भी LINQ विधि की तरह कह सकते हैं:

myObservableCollection.Sort(o => o.MyProperty);

2
एक अतिरिक्त चॉकलेट कुकी के लिए आप एक बूलियन पैरामीटर "आरोही" और if(!Ascending) sorted.Reverse();इससे ठीक पहले जोड़ सकते हैं for: D (और कोई ज़रूरत नहीं है- मेमोरी की चिंता करते हुए, कि रिवर्स विधि कोई नई ऑब्जेक्ट नहीं बनाता है, यह इन-प्लेस रिवर्स है
तेजस्वी

मेरे परीक्षण संग्रह के अनुसार। मोवे (0,0) एक संग्रहित घटना की ओर जाता है। इसलिए यह एक कदम है कि पहले भी जाँच करने के लिए एक प्रदर्शन कामचलाऊ व्यवस्था होगी।
sa.he

10

मैं नील के जवाब में जोड़ना चाहूंगा । एक ऐसी विधि को शामिल करना जो क्रम से मिलता जुलता हो। इस विधि को एक्सटेंशन के रूप में जोड़ें:

public static void Sort<T>(this ObservableCollection<T> collection, Func<T,T> keySelector) where T : IComparable
{
    List<T> sorted = collection.OrderBy(keySelector).ToList();
    for (int i = 0; i < sorted.Count(); i++)
        collection.Move(collection.IndexOf(sorted[i]), i);
}

और जैसे उपयोग करें:

myCollection = new ObservableCollection<MyObject>();

//Sorts in place, on a specific Func<T,T>
myCollection.Sort(x => x.ID);

8

एक भिन्नता वह जगह है जहां आप चयन सॉर्ट एल्गोरिथ्म का उपयोग करके संग्रह को सॉर्ट करते हैं। तत्वों का उपयोग Moveविधि में किया जाता है। प्रत्येक चाल CollectionChangedघटना को NotifyCollectionChangedAction.Move(और PropertyChangedसंपत्ति के नाम के साथ भी Item[]) आग देगी ।

इस एल्गोरिथ्म में कुछ अच्छे गुण हैं:

  • एल्गोरिथ्म को एक स्थिर प्रकार के रूप में लागू किया जा सकता है।
  • संग्रह में स्थानांतरित किए गए आइटमों की संख्या (उदाहरण के लिए CollectionChangedनिकाल दी गई घटनाएँ) सम्मिलन प्रकार और बबल सॉर्ट जैसे अन्य समान एल्गोरिदम से लगभग हमेशा कम होती है।

एल्गोरिथ्म काफी सरल है। संग्रह को सबसे छोटे तत्व को खोजने के लिए पुनरावृत्त किया जाता है जिसे बाद में संग्रह के प्रारंभ में स्थानांतरित कर दिया जाता है। प्रक्रिया को दूसरे तत्व पर शुरू किया जाता है और इसी तरह से जब तक सभी तत्वों को स्थानांतरित नहीं किया जाता है। एल्गोरिथ्म बहुत कुशल नहीं है, लेकिन किसी भी चीज़ के लिए आप एक उपयोगकर्ता इंटरफ़ेस में प्रदर्शित करने जा रहे हैं, इससे कोई फर्क नहीं पड़ता। हालांकि, चाल कार्यों की संख्या के संदर्भ में यह काफी कुशल है।

यहाँ एक विस्तार विधि है जो सादगी के लिए आवश्यक है कि तत्व कार्यान्वित हों IComparable<T>। अन्य विकल्प IComparer<T>a या a का उपयोग कर रहे हैं Func<T, T, Int32>

public static class ObservableCollectionExtensions {

  public static void Sort<T>(this ObservableCollection<T> collection) where T : IComparable<T> {
    if (collection == null)
      throw new ArgumentNullException("collection");

    for (var startIndex = 0; startIndex < collection.Count - 1; startIndex += 1) {
      var indexOfSmallestItem = startIndex;
      for (var i = startIndex + 1; i < collection.Count; i += 1)
        if (collection[i].CompareTo(collection[indexOfSmallestItem]) < 0)
          indexOfSmallestItem = i;
      if (indexOfSmallestItem != startIndex)
        collection.Move(indexOfSmallestItem, startIndex);
    }
  }

}

संग्रह को क्रमबद्ध करना विस्तार विधि को लागू करने की बात है:

var collection = new ObservableCollection<String>(...);
collection.Sort();

1
यह यहाँ वर्णित सभी से मेरा पसंदीदा सॉर्टिंग तरीका है, दुर्भाग्य से सिल्वरलाइट में मूव विधि उपलब्ध नहीं है 5.
एडुआर्डो ब्राइट्स

1
Im त्रुटि 'Profiler.Profile.ProfileObject' को सामान्य प्रकार या विधि 'ObservableCollectionExtensions.Sort <T> (ObservableCollection / T>)' में टाइप पैरामीटर 'T' के रूप में उपयोग नहीं किया जा सकता है। 'Profiler.Profile.ProfileObject' से 'System.IComparable <Profiler.Profile.ProfileObject>
New Bee

1
@ न्यूबाई: यह एक्सटेंशन विधि संग्रह में तत्वों को सॉर्ट करने में सक्षम होने के लिए एक सामान्य बाधा को निर्दिष्ट करती है T। सॉर्टिंग में अधिक से अधिक और कम की अवधारणा शामिल है और केवल आप परिभाषित कर सकते हैं कि कैसे ProfileObjectऑर्डर किया गया है। एक्सटेंशन पद्धति का उपयोग करने के लिए आपको इसे लागू IComparable<ProfileObject>करना होगा ProfileObject। अन्य विकल्प के रूप में एक IComparer<ProfileObject>या एक निर्दिष्ट निर्दिष्ट कर रहे हैं Func<ProfileObject, ProfileObject, int>और तदनुसार कोडिंग बदल जाते हैं।
मार्टिन लीवरेज

4

Xr280xr उत्तर पर विस्तार विधि को थोड़ा सुधारने के लिए मैंने एक वैकल्पिक बूल पैरामीटर जोड़ा ताकि यह निर्धारित किया जा सके कि छँटाई अवरोही है या नहीं। मैंने उस उत्तर के लिए कार्लोस पी द्वारा दिए गए सुझाव को भी टिप्पणी में शामिल किया। कृपया नीचे देखे।

public static void Sort<TSource, TKey>(this ObservableCollection<TSource> source, Func<TSource, TKey> keySelector, bool desc = false)
    {
        if (source == null) return;

        Comparer<TKey> comparer = Comparer<TKey>.Default;

        for (int i = source.Count - 1; i >= 0; i--)
        {
            for (int j = 1; j <= i; j++)
            {
                TSource o1 = source[j - 1];
                TSource o2 = source[j];
                int comparison = comparer.Compare(keySelector(o1), keySelector(o2));
                if (desc && comparison < 0)
                    source.Move(j, j - 1);
                else if (!desc && comparison > 0)
                    source.Move(j - 1, j);
            }
        }
    }

2

क्या आपको हर समय अपने संग्रह को क्रमबद्ध रखने की आवश्यकता है? जोड़े को पुन: प्राप्त करते समय, क्या आपको उन्हें हमेशा हल करने की आवश्यकता है, या यह केवल कुछ समय के लिए है (शायद सिर्फ प्रस्तुत करने के लिए)? आप अपने संग्रह के कितने बड़े होने की उम्मीद करते हैं? बहुत सारे कारक हैं जो आपको डायन विधि का उपयोग करने का निर्णय लेने में मदद कर सकते हैं।

यदि आपको संग्रह को हर समय क्रमबद्ध करने की आवश्यकता है, तब भी जब आप तत्वों को सम्मिलित करते हैं या हटाते हैं और सम्मिलन की गति कोई समस्या नहीं है, तो शायद आपको किसी प्रकार के SortedObservableCollection@Gerrie Schenck का उल्लेख करना चाहिए या इस कार्यान्वयन की जाँच करनी चाहिए ।

यदि आपको अपने संग्रह की जरूरत है तो बस कुछ समय के लिए उपयोग करें:

my_collection.OrderBy(p => p.Key);

संग्रह को सॉर्ट करने में कुछ समय लगेगा, लेकिन फिर भी, यह आपके साथ क्या कर रहा है, इसके आधार पर सबसे अच्छा समाधान हो सकता है।


1
इस उत्तर में लिंक LGPL लाइसेंस कोड के लिए है, इसलिए यदि आप सिल्वरलाइट हैं (गतिशील रूप से लिंक नहीं कर सकते हैं) या खुला स्रोत उस कोड से सावधान रहें।
yzorg

2

मेरे वर्तमान उत्तर में पहले से ही सबसे अधिक वोट हैं, लेकिन मुझे ऐसा करने का एक बेहतर और अधिक आधुनिक तरीका मिला।

class MyObject 
{
      public int id { get; set; }
      public string title { get; set; }
}

ObservableCollection<MyObject> myCollection = new ObservableCollection<MyObject>();

//add stuff to collection
// .
// .
// .

myCollection = new ObservableCollection<MyObject>(
    myCollection.OrderBy(n => n.title, Comparer<string>.Create(
    (x, y) => (Utils.Utils.LogicalStringCompare(x, y)))));

मूल उत्तर को अपडेट करना बेहतर नहीं होगा?
नाथन ह्यूजेस

नहीं, यह पहले से ही किसी भी अन्य उत्तर से अधिक उत्कीर्ण किया गया है। मैं मानने वाला नहीं हूं कि लोग इस तरह से करेंगे। बस मैंने सोचा कि मैं इसे करने का एक और तरीका पेश करूंगा, खासकर जब से नए उत्तरों पर इनाम था।
NielW

1

एक नया वर्ग बनाएं SortedObservableCollection, इसे ObservableCollectionलागू करें और कार्यान्वित करें IComparable<Pair<ushort, string>>


1

एक तरीका यह होगा कि इसे एक सूची में परिवर्तित किया जाए और फिर एक सॉर्टिंग प्रतिनिधि प्रदान करते हुए सॉर्ट () को कॉल करें। कुछ इस तरह:-

(Untested)

my_collection.ToList().Sort((left, right) => left == right ? 0 : (left > right ? -1 : 1));


1

क्या बिल्ली, मैं एक जल्दी से cobbled के साथ-साथ जवाब में फेंक देंगे ... यह यहाँ कुछ अन्य कार्यान्वयन की तरह एक सा दिखता है, लेकिन मैं इसे किसी भी जोड़ दूंगा:

(मुश्किल से परीक्षण, उम्मीद है कि मैं खुद को शर्मिंदा नहीं कर रहा हूँ)

आइए कुछ लक्ष्यों को पहले बताएं (मेरी धारणाएं):

1) ObservableCollection<T>सूचनाओं को बनाए रखने, आदि के लिए जगह में छाँटना चाहिए ।

2) भयानक रूप से अक्षम नहीं होना चाहिए (यानी, मानक "अच्छा" छँटाई दक्षता के करीब )

public static class Ext
{
    public static void Sort<T>(this ObservableCollection<T> src)
        where T : IComparable<T>
    {
        // Some preliminary safety checks
        if(src == null) throw new ArgumentNullException("src");
        if(!src.Any()) return;

        // N for the select,
        // + ~ N log N, assuming "smart" sort implementation on the OrderBy
        // Total: N log N + N (est)
        var indexedPairs = src
            .Select((item,i) => Tuple.Create(i, item))
            .OrderBy(tup => tup.Item2);
        // N for another select
        var postIndexedPairs = indexedPairs
            .Select((item,i) => Tuple.Create(i, item.Item1, item.Item2));
        // N for a loop over every element
        var pairEnum = postIndexedPairs.GetEnumerator();
        pairEnum.MoveNext();
        for(int idx = 0; idx < src.Count; idx++, pairEnum.MoveNext())
        {
            src.RemoveAt(pairEnum.Current.Item1);
            src.Insert(idx, pairEnum.Current.Item3);            
        }
        // (very roughly) Estimated Complexity: 
        // N log N + N + N + N
        // == N log N + 3N
    }
}

1

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

public class ScoutItems : ObservableCollection<ScoutItem>
{
    public void Sort(SortDirection _sDir, string _sItem)
    {
             //TODO: Add logic to look at _sItem and decide what property to sort on
            IEnumerable<ScoutItem> si_enum = this.AsEnumerable();

            if (_sDir == SortDirection.Ascending)
            {
                si_enum = si_enum.OrderBy(p => p.UPC).AsEnumerable();
            } else
            {
                si_enum = si_enum.OrderByDescending(p => p.UPC).AsEnumerable();
            }

            foreach (ScoutItem si in si_enum)
            {
                int _OldIndex = this.IndexOf(si);
                int _NewIndex = si_enum.ToList().IndexOf(si);
                this.MoveItem(_OldIndex, _NewIndex);
            }
      }
}

... जहां स्काउट इट मेरा सार्वजनिक वर्ग है। बस बहुत सरल लग रहा था। जोड़ा गया लाभ: यह वास्तव में काम करता है और बाइंडिंग के साथ गड़बड़ नहीं करता है या एक नया संग्रह वापस नहीं करता है आदि।


1

ठीक है, चूँकि मुझे XAML के साथ काम करने के लिए ऑब्जर्वेबलश्र्डलिस्ट मिल रहे थे, इसलिए मैंने आगे बढ़कर SortingObservableCollection बनाया । यह ओब्जर्वेबल कॉलेलेशन से विरासत में मिला है, इसलिए यह XAML के साथ काम करता है और मैंने इसे 98% कोड कवरेज पर परीक्षण किया है। मैंने इसे अपने ऐप्स में उपयोग किया है, लेकिन मैं यह वादा नहीं करूंगा कि यह बग मुक्त है। बेहिचक योगदान दें। यहाँ नमूना कोड उपयोग है:

var collection = new SortingObservableCollection<MyViewModel, int>(Comparer<int>.Default, model => model.IntPropertyToSortOn);

collection.Add(new MyViewModel(3));
collection.Add(new MyViewModel(1));
collection.Add(new MyViewModel(2));
// At this point, the order is 1, 2, 3
collection[0].IntPropertyToSortOn = 4; // As long as IntPropertyToSortOn uses INotifyPropertyChanged, this will cause the collection to resort correctly

यह एक पीसीएल है, इसलिए इसे विंडोज स्टोर, विंडोज फोन और .NET 4.5.1 के साथ काम करना चाहिए।


1
आपको शायद newउन सभी तरीकों का उपयोग नहीं करना चाहिए , अगर किसी के पास अधिक उदार रूप से टाइप किया गया उदाहरण है, तो उन तरीकों को नहीं बुलाया जाएगा। overrideहर अतिव्याप्त विधि के बजाय और उन्हें आवश्यक रूप से बदल दें या कमबैक करें base.Method(...)। उदाहरण के लिए, आपको इस बारे में चिंता करने की आवश्यकता नहीं है .Addक्योंकि आंतरिक रूप से उपयोग किया जाता है .InsertItem, इसलिए यदि .InsertItemओवरराइड किया गया और समायोजित किया गया, .Addतो ऑर्डर करने में कोई गड़बड़ नहीं होगी।
एचबी

1

यही मैं OC एक्सटेंशन के साथ करता हूं:

    /// <summary>
    /// Synches the collection items to the target collection items.
    /// This does not observe sort order.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="source">The items.</param>
    /// <param name="updatedCollection">The updated collection.</param>
    public static void SynchCollection<T>(this IList<T> source, IEnumerable<T> updatedCollection)
    {
        // Evaluate
        if (updatedCollection == null) return;

        // Make a list
        var collectionArray = updatedCollection.ToArray();

        // Remove items from FilteredViewItems not in list
        source.RemoveRange(source.Except(collectionArray));

        // Add items not in FilteredViewItems that are in list
        source.AddRange(collectionArray.Except(source));
    }

    /// <summary>
    /// Synches the collection items to the target collection items.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="source">The source.</param>
    /// <param name="updatedCollection">The updated collection.</param>
    /// <param name="canSort">if set to <c>true</c> [can sort].</param>
    public static void SynchCollection<T>(this ObservableCollection<T> source,
        IList<T> updatedCollection, bool canSort = false)
    {
        // Synch collection
        SynchCollection(source, updatedCollection.AsEnumerable());

        // Sort collection
        if (!canSort) return;

        // Update indexes as needed
        for (var i = 0; i < updatedCollection.Count; i++)
        {
            // Index of new location
            var index = source.IndexOf(updatedCollection[i]);
            if (index == i) continue;

            // Move item to new index if it has changed.
            source.Move(index, i);
        }
    }

1

यह मेरे लिए काम करता है, यह बहुत समय पहले कहीं मिला था।

// SortableObservableCollection
public class SortableObservableCollection<T> : ObservableCollection<T>
    {
        public SortableObservableCollection(List<T> list)
            : base(list)
        {
        }

        public SortableObservableCollection()
        {
        }

        public void Sort<TKey>(Func<T, TKey> keySelector, System.ComponentModel.ListSortDirection direction)
        {
            switch (direction)
            {
                case System.ComponentModel.ListSortDirection.Ascending:
                    {
                        ApplySort(Items.OrderBy(keySelector));
                        break;
                    }
                case System.ComponentModel.ListSortDirection.Descending:
                    {
                        ApplySort(Items.OrderByDescending(keySelector));
                        break;
                    }
            }
        }

        public void Sort<TKey>(Func<T, TKey> keySelector, IComparer<TKey> comparer)
        {
            ApplySort(Items.OrderBy(keySelector, comparer));
        }

        private void ApplySort(IEnumerable<T> sortedItems)
        {
            var sortedItemsList = sortedItems.ToList();

            foreach (var item in sortedItemsList)
            {
                Move(IndexOf(item), sortedItemsList.IndexOf(item));
            }
        }
    }

उपयोग:

MySortableCollection.Sort(x => x, System.ComponentModel.ListSortDirection.Ascending);

0

मुझे सिर्फ एक ही नहीं बल्कि कई चीजों के आधार पर छांटने की जरूरत है। यह उत्तर कुछ अन्य उत्तरों पर आधारित है, लेकिन यह अधिक जटिल छंटाई की अनुमति देता है।

static class Extensions
{
    public static void Sort<T, TKey>(this ObservableCollection<T> collection, Func<ObservableCollection<T>, TKey> sort)
    {
        var sorted = (sort.Invoke(collection) as IOrderedEnumerable<T>).ToArray();
        for (int i = 0; i < sorted.Count(); i++)
            collection.Move(collection.IndexOf(sorted[i]), i);
    }
}

जब आप इसका उपयोग करते हैं, तो ऑर्डरबी / तब कॉल की एक श्रृंखला में पास करें। ऐशे ही:

Children.Sort(col => col.OrderByDescending(xx => xx.ItemType == "drive")
                    .ThenByDescending(xx => xx.ItemType == "folder")
                    .ThenBy(xx => xx.Path));

0

मैंने अन्य समाधानों से बहुत कुछ सीखा, लेकिन मुझे कुछ समस्याएं मिलीं। सबसे पहले, कुछ IndexOf पर निर्भर करते हैं जो बड़ी सूचियों के लिए बहुत धीमा हो जाता है। दूसरा, मेरे ऑब्ज़र्वेबल कॉलेक्शन में EF इकाइयाँ थीं और Remove का उपयोग करने से कुछ विदेशी प्रमुख संपत्तियाँ भ्रष्ट हो गईं। शायद मैं कुछ गलत कर रहा हूं।

भले ही, ए हट / इंसर्ट के बजाय ए मूव का इस्तेमाल किया जा सकता है, लेकिन इससे कुछ समस्याएं परफॉर्मेंस फिक्स हो जाती हैं।

प्रदर्शन की समस्या को ठीक करने के लिए, मैं IndexOf सॉर्ट किए गए मानों के साथ एक शब्दकोश बनाता हूं। शब्दकोश को अप-टू-डेट रखने और इकाई गुणों को संरक्षित करने के लिए, अन्य समाधानों में लागू किए गए एक के बजाय दो चालों के साथ लागू किए गए स्वैप का उपयोग करें।

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

public static void Sort<TSource, TKey>(this ObservableCollection<TSource> collection, Func<TSource, TKey> keySelector)
{
    List<TSource> sorted = collection.OrderBy(keySelector).ToList();
    Dictionary<TSource, int> indexOf = new Dictionary<TSource, int>();

    for (int i = 0; i < sorted.Count; i++)
        indexOf[sorted[i]] = i;

    int idx = 0;
    while (idx < sorted.Count)
        if (!collection[idx].Equals(sorted[idx])) {
            int newIdx = indexOf[collection[idx]]; // where should current item go?
            collection.Move(newIdx, idx); // move whatever's there to current location
            collection.Move(idx + 1, newIdx); // move current item to proper location
        }
        else {
            idx++;
        }
}

-3
var collection = new ObservableCollection<int>();

collection.Add(7);
collection.Add(4);
collection.Add(12);
collection.Add(1);
collection.Add(20);

// ascending
collection = new ObservableCollection<int>(collection.OrderBy(a => a));

// descending
collection = new ObservableCollection<int>(collection.OrderByDescending(a => a));

ओह, मैं समझ गया ... गेयोट सबसे नीचे जवाब देने के लिए इनाम देना चाहता था lol
NielW

कभी व्यंग्य में पुरस्कार देते हुए नहीं देखा गया :)
nawfal
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.