简体   繁体   English

用于收集集合的代码片段 <T> 基于逗号分隔的字符串值

[英]Codesnippet for sorting collection<T> based on a comma-separated string value

In my code I use a collection<T> as binding source for different controls (WPF/C#). 在我的代码中,我使用collection<T>作为不同控件(WPF / C#)的绑定源。 The collection is created from the system every time the application loads. 每次加载应用程序时,都会从系统创建集合。 I don't have control on the collection and its order (items within the collection) are randomly for every launch of the app. 我无法控制集合,并且每次启动应用程序时,它的顺序(集合中的项目)都是随机的。

For UI reasons I need to allow to sort the collection, display it in a listview and keep the sorting when modified by the user (moveup and movedown buttons). 出于UI的原因,我需要允许对集合进行排序,将其显示在列表视图中,并在用户修改时保持排序(上移和下移按钮)。 Therefore my Idea was simple. 因此,我的想法很简单。 I simply write the items comma-separated into a hidden string variable eg. 我只是将逗号分隔的项目写成一个隐藏的字符串变量,例如。 "itemX,ItemY,ItemZ" . "itemX,ItemY,ItemZ"

Now I need a function that sorts the collection based on the string. 现在,我需要一个基于字符串对集合进行排序的函数。 I was thinking of a few foreach loops, but I am sure there is a better way of sorting the collection. 我当时在想几个foreach循环,但是我确信有一个更好的排序集合的方法。

  • sort the Items within collection<t> in the same order as represented by the string. 按照字符串表示的顺序对collection<t>中的项目进行排序。

     string correctItemOrder = "Application5, Application2, Application4, Application3". 

Collection<T> has items with just the property name (eg "Applicaton3" ) but is sorted randomly. Collection<T>具有仅具有属性名称的项目(例如"Applicaton3" ),但是是随机排序的。 I want to sort the collection in the same order as the string. 我想按与字符串相同的顺序对集合进行排序。

T is an interface an I can access a property "Name" that has the value that is stored in the string eg. T是一个接口,我可以访问属性"Name" ,该属性的值存储在例如字符串中。 "ItemX". “ ItemX”。

Any cool snippets/functions? 有什么不错的摘要/功能吗?

Thanks 谢谢

A couple of ideas... 几个想法...

Either way, you'll want your "item order string" as an array, so... 无论哪种方式,您都希望将“商品订单字符串”作为数组,所以...

var sortOrder = correctItemOrder.Split(new[] { ", " }, StringSplitOptions.None);

Then one option is to order your collection by the order of items in sortOrder (meaning you have to traverse through half of sortOrder, on average, for each element in your collection): 然后,一种选择是按照sortOrder中项目的顺序对集合进行排序(这意味着对于集合中的每个元素,平均必须遍历sortOrder的一半):

var sortedCollection = new Collection<T>(collection.OrderBy(x => Array.IndexOf(sortOrder, x.Name)).ToList());

Another option is to create a dictionary of Name => item, then traverse sortOrder, selecting items from this dictionary as you go... 另一个选择是创建一个Name => item的字典,然后遍历sortOrder,并从该字典中选择项目。

var dict = collection.ToDictionary(x => x.Name);
var sortedCollection = new Collection<T>(sortOrder.Select(x => dict[x]).ToList());

It's worth noting that if new items are added to the collection, but not sortOrder, the first snippet will place them at the start of the collection, whereas the second one will discard them entirely. 值得注意的是,如果将新项目添加到集合中,但未添加sortOrder,则第一个代码段会将其放置在集合的开始,而第二个代码段将完全丢弃它们。 Similarly if items are present in sortOrder but not the collection, the first snippet will ignore them, whereas the second one will throw an exception. 同样,如果项目存在于sortOrder中,但不存在于集合中,则第一个代码段将忽略它们,而第二个代码段将引发异常。

EDIT: 编辑:

The third option, of course, is to create dictionary from sortOrder, and use that. 当然,第三个选项是从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());

EDIT2: 编辑2:

As Enigmativity has pointed out, using lookups instead of dictionaries allows you to handle the cases where dictionary keys are missing very neatly. 正如Enigmativity指出的那样,使用查找而不是字典可以让您处理字典键非常整齐地丢失的情况。

The last example using this technique: 使用此技术的最后一个示例:

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());

I think a comparer like this should do the job: 我认为这样的比较器应该可以完成这项工作:

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();
    }

EDIT: I see that Collection has not order by itself, so is needed to build a wrapper 编辑:我看到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); 
    }
  }

This way you can sort the colection when you need it doing: 这样,您可以在需要时对集合进行排序:

     your_collection.Sort();

You could do this: 您可以这样做:

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;

This handles missing values in the correctItemOrder string too. 这也可以处理correctItemOrder字符串中的缺失值。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM