簡體   English   中英

用於收集集合的代碼片段 <T> 基於逗號分隔的字符串值

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM