0

我有那个课

public class MyItem
{
    public Order OrderItem { get; set; }
    public string Status { get; set; }
}

Status属性可以有值Error, Pending,Success

我想根据属性对List<MyItem>()对象进行排序Status

我知道我可以将Status属性的类型从stringto替换为, ,int而不是我可以拥有的值, ,然后排序操作很简单。但是我想知道如果我们必须根据type 属性进行排序,该怎么做。ErrorPendingSuccess123string

可能的顺序:

Error, Pending,SuccessSuccess, Pending,Error

如何通过使用 LINQ 来做到这一点?

4

8 回答 8

5

我会使用一个enum默认情况下给每个状态一个整数值,例如

public enum Status
{
    Success,
    Pending,
    Error
}

var sortedList = myList.OrderBy(x => x.Status);
// sort by Success, Pending and then Error
var sortedList = myList.OrderByDescending(x => x.Status);
// sort by Error, Pending, Success

您可以enum很容易地将现有字符串转换为:

var status = (Status)Enum.Parse(typeof(Status), statusString);
于 2013-06-06T10:28:01.957 回答
4

最好解析为enum但是,您可以制作一个自定义比较器,

var customComparer = Comparer<string>.Create((x, y) =>
    {
        ...
    });

您可以将比较器传递给按函数排序和排序,如下所示,

var sortedList = myList.OrderBy(x => x.Status, customComparer);
于 2013-06-06T10:33:11.697 回答
3

最简单的方法可能是实现IComparable<T>接口。在您的类上实现此接口MyItem将确保在对实例列表进行排序时,将使用方法MyItem中指定的排序。CompareTo对于您的用例,这将导致如下代码:

public class MyItem : IComparable<MyItem>
{
    public string OrderItem { get; set; }
    public string Status { get; set; }

    public int CompareTo(MyItem other)
    {
        if (other == null)
        {
            return 1;
        }

        if (other.Status == this.Status)
        {
            return 0;
        }

        var statusAsInt = this.Status == "Error" ? 0 : (this.Status == "Pending" ? 1 : 2);
        var otherStatusAsInt = other.Status == "Error" ? 0 : (other.Status == "Pending" ? 1 : 2);

        if (statusAsInt == otherStatusAsInt)
        {
            return 0;
        }

        return statusAsInt < otherStatusAsInt ? -1 : 1;
    }
}

internal class Program
{
    private static void Main(string[] args)
    {
        var myItems = new List<MyItem> { new MyItem { Status = "Pending" }, new MyItem { Status = "Error" }, new MyItem { Status = "Success " } };

        myItems.Sort();

        foreach (var myItem in myItems)
        {
            Console.WriteLine(myItem.Status);
        }    
    }
}
于 2013-06-06T10:32:05.270 回答
2

您可以定义一个反映所需排序的字典

Dictionary<string, int> ordering = new Dictionary<string, int> {
  { "Error", 1 },
  { "Pending", 2 },
  ...
}

var sortedList = myList.OrderBy(x => ordering[x.Status]);
于 2013-06-06T10:32:38.267 回答
1

我认为最好更改 Status 的类型并将 String 替换为枚举。然后,您可以通过为枚举的不同成员分配值来选择所需的顺序,或者根据您的 order 方法直接对该成员进行排序,并保留一个可读的属性。

于 2013-06-06T10:28:38.263 回答
1

由于订单恰好是按字母顺序排列的,您可以做一个简单的

var result = myList.OrderBy(item => item.Status);

或者

var result = myList.OrderByDescending(item => item.Status);

但是,如果您将“成功”重命名为“完成”,那么它会中断,在这种情况下,我会推荐其中一个建议的enum答案。

于 2013-06-06T10:32:12.317 回答
0

我会选择 Enum 选项,但鉴于它不是您的首选选项,您可以尝试以下操作:

您可以IComparable<MyItem>在课堂上实施MyItem

在那里根据 Status 属性实现您的排序逻辑。如果两个状态相同,您甚至可以按 OrderItem 订购,如果这适合您的话。

如果你需要一个例子,请随意说

于 2013-06-06T10:33:41.000 回答
0

您可以通过 .OrderBy() 使用这样的开关对字符串进行加权的方法:

     List<MyItem> lst = new List<MyItem>();

     lst.Add(new MyItem() { Status = "Pending" });
     lst.Add(new MyItem() { Status = "Error" });
     lst.Add(new MyItem() { Status = "Invalid String" });
     lst.Add(new MyItem() { Status = "Success" });

     var ascList =
        lst.OrderBy((x) => { switch (x.Status) { case "Error": return 0; case "Pending": return 1; case "Success": return 3; default: return 4; } });

     var descList =
        lst.OrderByDescending((x) => { switch (x.Status) { case "Error": return 0; case "Pending": return 1; case "Success": return 3; default: return 4; } });

     Console.WriteLine("Asc\n===");
     foreach (MyItem mi in ascList)
     {
        Console.WriteLine(mi.Status);
     }

     Console.WriteLine("\nDesc\n====");
     foreach (MyItem mi in descList)
     {
        Console.WriteLine(mi.Status);
     }
  }
于 2013-06-06T10:45:39.663 回答