在 C# 中,按字符串属性对对象列表进行排序并获得正确顺序的最佳方法是什么?

问题描述 投票:0回答:6

我有一个“问题”对象列表,我想按“优先级”字段对它们进行排序。

问题是“优先级”是一个字符串名称,如“HIGH”、“MEDIUM”,所以我没有可以排序的 ID。如何排序并告诉排序器“HIGH”高于“MEDIUM”,“MEDIUM”又高于“LOW”?

c# linq collections
6个回答
10
投票

显而易见的方法是:

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

2
投票

最简单的方法可能是这样的:

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>


2
投票

在这种特定情况下,您还可以使用 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)。


1
投票
public enum Priority
{
    LOW = 1,
    MEDIUM = 2,
    HIGH = 3
}

issues.OrderByDescending(issue=>issue.Priority);

0
投票

类似这样的:

List<Issue> issues = ...;

var result = issues.OrderBy(x=> x.Priority=="HIGH"?1:x.Priority=="MEDIUM"?2:3);

0
投票

我最喜欢的解决方案是带有索引的字典:

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

中谈到过它
© www.soinside.com 2019 - 2024. All rights reserved.