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