Mam następującą klasę:
[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
}
Które umieściłem w ObservableCollection:
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"));
P: Jak to posortować według klucza?
Odpowiedzi:
Sortowanie obserwowalnego i zwracanie tego samego posortowanego obiektu można wykonać za pomocą metody rozszerzenia. W przypadku większych kolekcji uważaj na liczbę powiadomień o zmianach kolekcji.
Zaktualizowałem kod, aby poprawić wydajność i poradzić sobie z duplikatami (dzięki nawfalowi za podkreślenie słabej wydajności oryginału, mimo że działał dobrze na przykładzie oryginalnych danych). To, co obserwowalne, jest podzielone na sortowaną po lewej stronie i prawą nieposortowaną połowę, gdzie za każdym razem minimalna pozycja (taka, jaką można znaleźć na posortowanej liście) jest przesuwana na koniec posortowanej partycji z nieposortowanej. Najgorszy przypadek O (n). Zasadniczo sortowanie przez wybór (patrz poniżej dla wyników).
użycie: próbka z obserwatorem (użyto klasy Person, aby było to proste)
Szczegóły postępu sortowania pokazujące, w jaki sposób kolekcja jest przestawiana:
Klasa Person implementuje zarówno IComparable, jak i IEquatable, przy czym ta ostatnia służy do minimalizowania zmian w kolekcji w celu zmniejszenia liczby zgłaszanych powiadomień o zmianach
Aby zwrócić ObservableCollection, wywołaj .ToObservableCollection na * sortOC * używając np. [Ta implementacja] [1].
**** orig odpowiedź - tworzy to nową kolekcję **** Możesz użyć linq, jak ilustruje poniższa metoda doSort. Krótki fragment kodu: produkuje
3: xey 6: fty 7: aaa
Alternatywnie możesz użyć metody rozszerzenia w samej kolekcji
źródło
ObservableCollection
BinarySearch
zamiastIndexOf
.To proste rozszerzenie działało pięknie dla mnie. Po prostu musiałem się upewnić, że
MyObject
byłIComparable
. Gdy metoda sortowania jest wywoływana w obserwowalnej kolekcjiMyObjects
, wywoływana jestCompareTo
metoda onMyObject
, która wywołuje moją metodę Logical Sort. Chociaż nie ma wszystkich dzwonków i gwizdów z pozostałych odpowiedzi zamieszczonych tutaj, jest to dokładnie to, czego potrzebowałem.źródło
return Utils.LogicalStringCompare(a.Title, b.Title);
zamiastreturn string.Compare(a.Title, b.Title);
? @NeilWZnalazłem odpowiedni wpis na blogu, który zawiera lepszą odpowiedź niż te tutaj:
http://kiwigis.blogspot.com/2010/03/how-to-sort-obversablecollection.html
AKTUALIZACJA
ObservableSortedList że @romkyns podkreśla w komentarzach automatycznie utrzymuje porządek.
Zwróć jednak uwagę na uwagę
źródło
Możesz użyć tej prostej metody:
Możesz sortować w ten sposób:
Więcej szczegółów: http://jaider.net/2011-05-04/sort-a-observablecollection/
źródło
ObservableCollection
powiązany z ItemSource z list rozwijanych i w ogóle nie widzisz kolekcji. Również ta operacja usuwania i uzupełniania jest ultraszybka… „wolna” może być już zoptymalizowaną operacją. na koniec możesz zmodyfikować ten kod, aby zaimplementować metodę przenoszenia, posiadaniesortedlist
isource
reszta jest łatwa.Move
zdarzenia, także tylko dla naprawdę poruszonych.WPF zapewnia sortowanie na żywo natychmiast po wyjęciu z pudełka przy użyciu
ListCollectionView
klasy ...Po zakończeniu inicjalizacji nie ma już nic więcej do zrobienia. Zaletą w porównaniu z sortowaniem pasywnym jest to, że ListCollectionView wykonuje całe ciężkie podnoszenie w sposób przezroczysty dla dewelopera. Nowe elementy są automatycznie umieszczane we właściwej kolejności sortowania. Każda klasa, która pochodzi od
IComparer
T, jest odpowiednia dla niestandardowej właściwości sortowania.Zobacz ListCollectionView, aby uzyskać dokumentację i inne funkcje.
źródło
Podobało mi się podejście metody rozszerzania sortowania bąbelkowego na blogu „Richiego” powyżej, ale niekoniecznie chcę sortować, porównując cały obiekt. Częściej chcę sortować według określonej właściwości obiektu. Więc zmodyfikowałem go, aby akceptował selektor kluczy w sposób, w jaki robi to OrderBy, dzięki czemu możesz wybrać właściwość do sortowania:
Który można wywołać w ten sam sposób, w jaki wywołałbyś OrderBy, z wyjątkiem tego, że posortuje istniejące wystąpienie Twojej ObservableCollection zamiast zwracać nową kolekcję:
źródło
OrderBy
a następnie przeprowadzić porównanie, aby ustalić rzeczywistą zmianę.Odpowiedzią @ NielW jest droga do prawdziwego sortowania na miejscu. Chciałem dodać nieco zmienione rozwiązanie, które pozwala ominąć konieczność użycia
IComparable
:teraz możesz to nazwać jak większość każdej metody LINQ:
źródło
if(!Ascending) sorted.Reverse();
tuż przedfor
: D (i nie ma potrzeby - dalej - martwić się o pamięć, ta metoda Reverse nie tworzy żadnych nowych obiektów, jest odwrócona w miejscu)Chciałbym dodać do odpowiedzi NeilW . Włączenie metody, która przypomina orderby. Dodaj tę metodę jako rozszerzenie:
I używaj jak:
źródło
Odmiana polega na sortowaniu kolekcji w miejscu przy użyciu algorytmu sortowania przez wybór . Elementy są przenoszone na miejsce za pomocą tej
Move
metody. Każdy ruch spowoduje uruchomienieCollectionChanged
zdarzenia zNotifyCollectionChangedAction.Move
(a takżePropertyChanged
z nazwą właściwościItem[]
).Ten algorytm ma kilka fajnych właściwości:
CollectionChanged
Wywołanych zdarzeń) jest prawie zawsze mniejsza niż w przypadku innych podobnych algorytmów, takich jak sortowanie przez wstawianie i sortowanie bąbelkowe.Algorytm jest dość prosty. Kolekcja jest powtarzana w celu znalezienia najmniejszego elementu, który jest następnie przenoszony na początek kolekcji. Proces jest powtarzany, zaczynając od drugiego elementu i tak dalej, aż wszystkie elementy zostaną przesunięte na miejsce. Algorytm nie jest zbyt wydajny, ale w przypadku wszystkiego, co zamierzasz wyświetlić w interfejsie użytkownika, nie powinno to mieć znaczenia. Jednak pod względem liczby operacji przenoszenia jest dość wydajny.
Oto metoda rozszerzenia, która dla uproszczenia wymaga implementacji elementów
IComparable<T>
. Inne opcje używają plikuIComparer<T>
lub aFunc<T, T, Int32>
.Sortowanie kolekcji jest po prostu kwestią wywołania metody rozszerzającej:
źródło
T
celu móc sortować elementy w kolekcji. Sortowanie obejmuje koncepcje większe i mniejsze niż i tylko Ty możesz określić, jakProfileObject
jest uporządkowane. Aby użyć metody rozszerzenia, musisz zaimplementowaćIComparable<ProfileObject>
naProfileObject
. Inne alternatywy są, jak wspomniano, z podaniem znakuIComparer<ProfileObject>
lub aFunc<ProfileObject, ProfileObject, int>
i odpowiednio zmień kod sortowania.Aby nieco ulepszyć metodę rozszerzania odpowiedzi xr280xr, dodałem opcjonalny parametr bool, aby określić, czy sortowanie jest malejące, czy nie. W komentarzu do tej odpowiedzi zawarłem również sugestię Carlosa P. Patrz poniżej.
źródło
Czy musisz zawsze posortować swoją kolekcję? Czy podczas pobierania par trzeba je zawsze sortować, czy tylko kilka razy (może tylko do prezentacji)? Jak duża będzie Twoja kolekcja? Istnieje wiele czynników, które mogą pomóc w podjęciu decyzji o zastosowaniu metody czarownicy.
Jeśli chcesz, aby kolekcja była sortowana przez cały czas, nawet gdy
SortedObservableCollection
wstawiasz lub usuwasz elementy, a prędkość wstawiania nie stanowi problemu, może powinieneś zaimplementować coś takiego jak wspomniany @Gerrie Schenck lub sprawdzić tę implementację .Jeśli potrzebujesz posortować swoją kolekcję tylko kilka razy, użyj:
Posortowanie kolekcji zajmie trochę czasu, ale mimo wszystko może to być najlepsze rozwiązanie w zależności od tego, co z nią zrobisz.
źródło
Moja obecna odpowiedź ma już najwięcej głosów, ale znalazłem lepszy i nowocześniejszy sposób na zrobienie tego.
źródło
Utwórz nową klasę
SortedObservableCollection
, wyprowadź ją zObservableCollection
i zaimplementujIComparable<Pair<ushort, string>>
.źródło
Jednym ze sposobów byłoby przekonwertowanie go na Listę, a następnie wywołanie Sort (), zapewniając delegata porównania. Coś jak:-
(niesprawdzone)
źródło
Myślę, że to najbardziej eleganckie rozwiązanie:
http://www.xamlplayground.org/post/2009/07/18/Use-CollectionViewSource-effectively-in-MVVM-applications.aspx
źródło
Co do cholery, dorzucę też szybko zebraną odpowiedź ... wygląda trochę jak kilka innych implementacji tutaj, ale dodam to gdziekolwiek:
(ledwo przetestowane, mam nadzieję, że się nie zawstydzam)
Najpierw przedstawmy kilka celów (moje założenia):
1) Należy sortować
ObservableCollection<T>
na miejscu, aby zachować powiadomienia itp.2) Nie może być strasznie nieefektywne (tj. Coś zbliżonego do standardowej „dobrej” wydajności sortowania)
źródło
Żadna z tych odpowiedzi nie zadziałała w moim przypadku. Albo dlatego, że psuje wiązanie, albo wymaga tak dużo dodatkowego kodowania, że jest to koszmar, albo odpowiedź jest po prostu zepsuta. Oto kolejna prostsza odpowiedź, o której pomyślałem. Jest to dużo mniej kodu i pozostaje tą samą obserwowalną kolekcją z dodatkowym typem metody this.sort. Daj mi znać, jeśli jest jakiś powód, dla którego nie powinienem tego robić w ten sposób (efektywność itp.)?
... Gdzie ScoutItem jest moją klasą publiczną. Po prostu wydawało się o wiele prostsze. Dodatkowa korzyść: faktycznie działa i nie psuje wiązań ani nie zwraca nowej kolekcji itp.
źródło
W porządku, ponieważ miałem problemy z uzyskaniem ObservableSortedList do pracy z XAML, poszedłem dalej i utworzyłem SortingObservableCollection . Dziedziczy po ObservableCollection, więc działa z XAML i przetestowałem go na poziomie 98% pokrycia kodu. Używałem go we własnych aplikacjach, ale nie obiecuję, że jest wolny od błędów. Zapraszam do udziału. Oto przykładowe użycie kodu:
Jest to PCL, więc powinien działać ze Sklepem Windows, Windows Phone i .NET 4.5.1.
źródło
new
na wszystkich tych metodach, jeśli ktoś ma instancję o bardziej typowym typie, te metody nie zostaną wywołane. Zamiast tegooverride
każdą możliwą do zastąpienia metodę i zmień ją w razie potrzeby lub skorzystaj z opcji zastępczejbase.Method(...)
. Na przykład nie musisz się nawet martwić,.Add
ponieważ to używa wewnętrznie.InsertItem
, więc jeśli.InsertItem
zostanie zastąpione i dostosowane,.Add
nie będzie bałaganu z zamawianiem.Oto, co robię z rozszerzeniami OC:
źródło
To zadziałało dla mnie, znalazłem to gdzieś dawno temu.
Stosowanie:
źródło
Musiałem mieć możliwość sortowania według wielu rzeczy, a nie tylko jednej. Ta odpowiedź jest oparta na niektórych innych odpowiedziach, ale pozwala na bardziej złożone sortowanie.
Kiedy go używasz, przekaż serię wywołań OrderBy / ThenBy. Lubię to:
źródło
Wiele się nauczyłem z innych rozwiązań, ale znalazłem kilka problemów. Po pierwsze, niektóre zależą od IndexOf, który wydaje się być dość powolny w przypadku dużych list. Po drugie, moja ObservableCollection miała jednostki EF i wydawało się, że użycie metody Remove uszkodziło niektóre właściwości klucza obcego. Może robię coś złego.
Niezależnie od tego, zamiast tego można użyć polecenia Usuń / Wstaw, ale powoduje to pewne problemy z poprawką wydajności.
Aby rozwiązać problem z wydajnością, tworzę słownik z posortowanymi wartościami IndexOf. Aby słownik był aktualny i aby zachować właściwości jednostki, użyj zamiany zaimplementowanej z dwoma ruchami zamiast jednego, jak zaimplementowano w innych rozwiązaniach.
Pojedynczy ruch przesuwa indeksy elementów między lokalizacjami, co mogłoby unieważnić słownik IndexOf. Dodanie drugiego ruchu w celu zaimplementowania zamiany przywraca lokalizacje.
źródło
źródło