我有一个“问题”对象列表,我想按“优先级”字段对它们进行排序。
问题是“优先级”是一个字符串名称,如“HIGH”、“MEDIUM”,所以我没有可以排序的 ID。如何排序并告诉排序器“HIGH”高于“MEDIUM”,“MEDIUM”又高于“LOW”?
显而易见的方法是:
string[] priorities = { "LOW", "MEDIUM", "HIGH" };
var orderedIssues = issues.OrderByDescending
(issue => Array.IndexOf(priorities, issue.Priority));
但考虑使用枚举:
public enum Priority
{
Low,
Medium,
High
}
var orderedIssues = issues.OrderByDescending
(issue => (Priority)Enum.Parse(typeof(Priority), issue.Priority, true));
更好的是使用枚举类型作为属性/字段本身的类型,在这种情况下,它就像简单(并且不易出错)一样:
var orderedIssues = issues.OrderByDescending(issue => issue.Priority);
最简单的方法可能是这样的:
private static int MapPriority(string priority)
{
switch(priority.ToUpperInvariant())//skip the case bit if safe
{
case "HIGH":
return 1;
case "MEDIUM":
return 2;
case "LOW":
return 3;
default:
return 4;
}
}
var sorted = someCollection.OrderBy(i => MapPriority(i.PriorityProperty));
使用数据库支持的表单,您需要数据库中的一个可以调用的函数。这仅在内存中。
有很多可能的值,我会基于字典而不是手动代码。不过,在这种情况下,我会手动编写三个代码(除非使用的值可能会改变,否则基于字典的方法将成为唯一的方法,这会进一步复杂化)。
如果要对大量此类项目进行排序,或者多次调用,我会使用
IComparer<T>
实现,或者让项目本身实现 IComparable<T>
。
在这种特定情况下,您还可以使用 Linq 的
OrderBy
方法:
var sortedList = issueList.OrderBy(i=>
i.Priority == "HIGH"
? 1
: i.Priority == "MEDIUM"
? 2
: 3).ToList();
作为一句单行话,这还不错。您还可以按照您希望的排序顺序将字符串放入数组、列表或字典中(或者在字典的情况下包含排序顺序作为值)。
使用 OrderBy 的一个缺点是它不会影响源 List,除非您通过将 List 重新分配给结果来告诉它。在所有情况下,它将创建两个额外的集合; OrderBy 中内部使用的数组或列表(排序必须了解它们正在排序的整个集合)以及 ToList() 生成的 List。因此,这将需要 O(2N) 额外的内存,而 List.Sort() 可能就地(不确定是否确实如此,但它确实使用通常就地的 QuickSort)。
public enum Priority
{
LOW = 1,
MEDIUM = 2,
HIGH = 3
}
issues.OrderByDescending(issue=>issue.Priority);
类似这样的:
List<Issue> issues = ...;
var result = issues.OrderBy(x=> x.Priority=="HIGH"?1:x.Priority=="MEDIUM"?2:3);
我最喜欢的解决方案是带有索引的字典:
var priorities = new Dictionary<string, int>()
{
{ "HIGH", 0 },
{ "MEDIUM", 1 },
{ "LOW", 2 }, // You can also use a non-complete priority list (for example without "LOW")
};
// Order by priorities, if priorities doesn't contains string value, push item to end.
var result = issues
.OrderBy(x => priorities.GetValueOrDefault(key: x.Priority, defaultValue: priorities.Count + 1))
.ToList();
我还决定创建一个小型开源 nuget 库来解决这个问题。
安装
dotnet add package Kurnakov.PriorityOrder
代码示例
using PriorityOrder;
var result = issues
.OrderByPriority(x => x.Priority, "HIGH", "MEDIUM", "LOW") // Or with IEnumerable<string>
.ToList();
更多详情您可以在这里找到
附注你也可以使用枚举代替字符串,我在这个answer
中谈到过它