[英]Codesnippet for sorting collection<T> based on a comma-separated string value
在我的代碼中,我使用collection<T>
作為不同控件(WPF / C#)的綁定源。 每次加載應用程序時,都會從系統創建集合。 我無法控制集合,並且每次啟動應用程序時,它的順序(集合中的項目)都是隨機的。
出於UI的原因,我需要允許對集合進行排序,將其顯示在列表視圖中,並在用戶修改時保持排序(上移和下移按鈕)。 因此,我的想法很簡單。 我只是將逗號分隔的項目寫成一個隱藏的字符串變量,例如。 "itemX,ItemY,ItemZ"
。
現在,我需要一個基於字符串對集合進行排序的函數。 我當時在想幾個foreach循環,但是我確信有一個更好的排序集合的方法。
按照字符串表示的順序對collection<t>
中的項目進行排序。
string correctItemOrder = "Application5, Application2, Application4, Application3".
Collection<T>
具有僅具有屬性名稱的項目(例如"Applicaton3"
),但是是隨機排序的。 我想按與字符串相同的順序對集合進行排序。
T
是一個接口,我可以訪問屬性"Name"
,該屬性的值存儲在例如字符串中。 “ ItemX”。
有什么不錯的摘要/功能嗎?
謝謝
幾個想法...
無論哪種方式,您都希望將“商品訂單字符串”作為數組,所以...
var sortOrder = correctItemOrder.Split(new[] { ", " }, StringSplitOptions.None);
然后,一種選擇是按照sortOrder中項目的順序對集合進行排序(這意味着對於集合中的每個元素,平均必須遍歷sortOrder的一半):
var sortedCollection = new Collection<T>(collection.OrderBy(x => Array.IndexOf(sortOrder, x.Name)).ToList());
另一個選擇是創建一個Name => item的字典,然后遍歷sortOrder,並從該字典中選擇項目。
var dict = collection.ToDictionary(x => x.Name);
var sortedCollection = new Collection<T>(sortOrder.Select(x => dict[x]).ToList());
值得注意的是,如果將新項目添加到集合中,但未添加sortOrder,則第一個代碼段會將其放置在集合的開始,而第二個代碼段將完全丟棄它們。 同樣,如果項目存在於sortOrder中,但不存在於集合中,則第一個代碼段將忽略它們,而第二個代碼段將引發異常。
編輯:
當然,第三個選項是從sortOrder創建字典,然后使用它。
var dict = sortOrder.Select((x, i) => new { x, i }).ToDictionary(x => x.x, x => x.i);
var sortedCollection = new Collection<T>(collection.OrderBy(x => dict[x.Name]).ToList());
編輯2:
正如Enigmativity指出的那樣,使用查找而不是字典可以讓您處理字典鍵非常整齊地丟失的情況。
使用此技術的最后一個示例:
var lookup = sortOrder.Select((x, i) => new {x, i}).ToLookup(x => x.x, x => x.i);
var sortedCollection = new Collection<T>(collection.OrderBy(x => lookup[x.Name].DefaultIfEmpty(Int32.MaxValue).First()).ToList());
我認為這樣的比較器應該可以完成這項工作:
public interface INamed {
string Name {get;}
}
public class CustomComparer : Comparer<INamed> {
Dictionary<string, int> hash;
public CustomComparer( ) {
var tokens = "Application5, Application2, Application4, Application3"
.Split( ',' )
.Select( s => s.Trim( ) )
.ToArray( );
hash = Enumerable.Range(0, tokens.Length)
.ToDictionary( i => tokens[i] );
}
public override int Compare( INamed x, INamed y ) {
return hash[x.Name] - hash[y.Name];
}
public static readonly CustomComparer Default = new CustomComparer();
}
編輯:我看到Collection本身沒有排序,因此需要構建包裝器
class SortableCollection<T> : System.Collections.ObjectModel.Collection<T>
{
public SortableCollection() : this(new List<T>()) {}
public SortableCollection(List<T> list) : base(list) {}
public virtual void Sort() { ((List<T>)Items).Sort(); }
}
class CustomSortableCollection<T> : SortableCollection<T> where T: INamed
{
public override void Sort() {
((List<INamed>)Items).Sort(CustomComparer.Default);
}
}
這樣,您可以在需要時對集合進行排序:
your_collection.Sort();
您可以這樣做:
var rank =
correctItemOrder
.Split(',')
.Select((x, n) => new { x = x.Trim(), n, })
.ToLookup(z => z.x, z => z.x);
var query =
from i in items
orderby rank[i.Name]
.DefaultIfEmpty(int.MaxValue)
.First()
select i;
這也可以處理correctItemOrder
字符串中的缺失值。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.