다음 수업이 있습니다.
[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에 넣었습니다.
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"));
Q : 키별로 어떻게 정렬합니까?
답변
관찰 가능 항목을 정렬하고 정렬 된 동일한 객체를 반환하는 작업은 확장 메서드를 사용하여 수행 할 수 있습니다. 더 큰 컬렉션의 경우 컬렉션 변경 알림 수를주의하세요.
성능을 향상시키고 중복을 처리하기 위해 코드를 업데이트했습니다 (원래 데이터 예제에서는 잘 작동했지만 원본의 성능 저하를 강조한 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
}
사용법 : 관찰자가있는 샘플 (단순하게 유지하기 위해 Person 클래스 사용)
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,
Person 클래스는 IComparable과 IEquatable을 모두 구현합니다. 후자는 발생하는 변경 알림의 수를 줄이기 위해 컬렉션의 변경을 최소화하는 데 사용됩니다.
- 편집 새 복사본을 만들지 않고 동일한 컬렉션을 정렬합니다. *
ObservableCollection을 반환하려면 [this implementation] [1]과 같이 * sortedOC *에서 .ToObservableCollection을 호출합니다.
**** orig answer-이것은 새로운 컬렉션을 생성합니다 **** 아래의 doSort 메소드가 보여주는 것처럼 linq를 사용할 수 있습니다. 빠른 코드 스 니펫 : 생성
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;
}
}
답변
이 간단한 확장은 저에게 아름답게 작동했습니다. 난 그냥 그 확인했다 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();
답변
여기에있는 것보다 더 나은 답변을 제공하는 관련 블로그 항목을 찾았습니다.
http://kiwigis.blogspot.com/2010/03/how-to-sort-obversablecollection.html
최신 정보
ObservableSortedList 코멘트 아웃 @romkyns 포인트가 자동으로 정렬 순서를 유지하고있다.
항목을 정렬 된 순서로 유지하는 관찰 가능한 컬렉션을 구현합니다. 특히, 주문 변경을 초래하는 항목 속성 변경은 올바르게 처리됩니다.
그러나 비고도 참고
관련된 인터페이스의 상대적 복잡성과 상대적으로 열악한 문서로 인해 버그가있을 수 있습니다 ( https://stackoverflow.com/a/5883947/33080 참조 ).
답변
이 간단한 방법을 사용할 수 있습니다.
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/
답변
WPF는ListCollectionView
클래스를 사용하여 기본적으로 라이브 정렬을 제공합니다 .
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
T 는 사용자 지정 정렬 속성에 적합합니다.
문서 및 기타 기능 은 ListCollectionView 를 참조하십시오 .
답변
위의 “Richie”블로그에서 버블 정렬 확장 방법 접근 방식이 마음에 들었지만 전체 개체를 비교하는 것만으로 정렬하고 싶지는 않습니다. 나는 더 자주 개체의 특정 속성을 정렬하고 싶습니다. 그래서 OrderBy와 같은 방식으로 키 선택기를 허용하도록 수정하여 정렬 할 속성을 선택할 수 있습니다.
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의 기존 인스턴스를 정렬한다는 점을 제외하면 OrderBy를 호출하는 것과 동일한 방식으로 호출합니다.
ObservableCollection<Person> people = new ObservableCollection<Person>();
...
people.Sort(p => p.FirstName);
답변
@NielW의 대답은 실제 내부 정렬을위한 방법입니다. 사용하지 않아도되는 약간 변경된 솔루션을 추가하고 싶었습니다 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);