簡體   English   中英

Linq OrderBy子列表

[英]Linq OrderBy Sub List

我試圖執行一個相當簡單的順序,但似乎正在努力如何去做。 舉個例子,我有這兩個類。

public class Method
{
    public int Id { get; set; }

    public string Name { get; set; }

    public decimal Price { get; set; }

    public List<Slot> Slots { get; set; }
}

public class Slot
{
    public DateTime ExpectedDeliveryDate { get; set; }
}

使用下面的代碼我想通過最便宜的選項訂購,然后按最快的交貨日期訂購。

var methods = new List<Method>();

methods.Add(new Method { Id = 1, Name = "Standard", Price = 0M, Slots = new List<Slot> { new Slot { ExpectedDeliveryDate = DateTime.Now.AddDays(5).Date } } });
methods.Add(new Method { Id = 2, Name = "Super Fast Next Day", Price = 0M, Slots = new List<Slot> { new Slot { ExpectedDeliveryDate = DateTime.Now.AddDays(1).Date } } });

var b = methods.OrderBy(x => x.Price)
    .ThenBy(y => y.Slots.OrderBy(t => t.ExpectedDeliveryDate.Date)
        .ThenBy(t => t.ExpectedDeliveryDate.TimeOfDay))
            .ToList();

我遇到的麻煩是我收到一個運行時錯誤,指出“至少有一個對象必須實現IComparable”。

雖然我可以通過實現IComparable接口來解決這個問題,但我想知道是否可以這樣做。 我想如果我有這個代碼(見下文)就好了。

var slots = new List<Slot>();

slots.Add(new Slot { ExpectedDeliveryDate = DateTime.Now.AddDays(5).Date });
slots.Add(new Slot { ExpectedDeliveryDate = DateTime.Now.AddDays(1).Date });
slots.Add(new Slot { ExpectedDeliveryDate = DateTime.Now.AddDays(3).Date });
slots.Add(new Slot { ExpectedDeliveryDate = DateTime.Now.Date });

var d = slots.OrderBy(x => x.ExpectedDeliveryDate);

干杯,DS。

在上面的示例中為變量命名(例如xyz道歉:)可以復制和粘貼代碼以獲得操作樂趣。

編輯 - 更新以簡化代碼示例。 - 成功排序后的結果預期

Input
  ID     Name            Price    Slot
  1      Standard        0        DateTime.Now.AddDays(5).Date
  2      Super Fast      0        DateTime.Now.Date

Output
  2      Super Fast      0        DateTime.Now.Date  
  1      Standard        0        DateTime.Now.AddDays(5).Date

所以我的超快選項應該是最好的,因為它是最便宜的,當然有最快的交貨日期。

您可以使用Enumerable.Min()來選擇具有最早日期的插槽,如下所示:

        var query = deliveryMethods
            .OrderBy(x => x.Slots.Min(s => s.ExpectedDeliveryDate).Year)
            .ThenBy(x => x.Slots.Min(s => s.ExpectedDeliveryDate).Month)
            .ThenBy(x => x.Slots.Min(s => s.ExpectedDeliveryDate).Date)
            .ToList();

要不就

        var query = deliveryMethods
            .OrderBy(x => x.Slots.Min(s => s.ExpectedDeliveryDate.Date))
            .ToList();

請注意,當輸入序列為空並且最小化的類型是值類型時, Min()將拋出異常。 如果您想避免異常,可以這樣做:

        var query2 = deliveryMethods
            .OrderBy(x => x.Slots.Min(s => (DateTime?)(s.ExpectedDeliveryDate.Date)))
            .ToList();

通過將DateTime轉換為可空, Min()將為空序列返回null,而具有空槽列表的Method對象將被排序到開頭。

我想解釋為什么您在原始帖子中發布的嘗試無效:

var xyz = deliveryMethods
        .OrderBy(x => x.Slots.OrderBy(y => y.ExpectedDeliveryDate.Year))
        .ThenBy(x => x.Slots.OrderBy(y => y.ExpectedDeliveryDate.Month))
        .ThenBy(x => x.Slots.OrderBy(y => y.ExpectedDeliveryDate.Date))
        .ToList();

這是因為你的嵌套OrderBy在s OrderBy秒。

x.Slots.OrderBy(...)生成一個IEnumerable<Slot> ,所以你基本上是在告訴它“將這些IEnumerable<Slot>相互比較來決定交付方法的順序”。 但Linq不知道如何將IEnumerable<Slot>與另一個進行比較並確定哪一個先於另一個( IEnumerable<Slot>未實現IComparable<T> ),因此您收到錯誤。

正如另一位用戶所指出的那樣,答案就是給它一些可以比較的東西。 正如您后來澄清的那樣,這將是每種交付方式的最早時段:

var xyz = deliveryMethods
        .OrderBy(x => x.Slots.Min(y => y.ExpectedDeliveryDate))
        .ToList();

這將在假設每個傳遞方法至少有一個槽的情況下工作,但如果它們中的任何一個具有零槽(或者如果Slots為空),則將拋出運行時異常。 我曾兩次問過你應該做些什么,我鼓勵你澄清一下。

一種可能的解決方案是僅包含具有插槽的交付方法:

var xyz = deliveryMethods
        .Where(x => x.Slots != null && x.Slots.Any())
        .OrderBy(x => x.Slots.Min(y => y.ExpectedDeliveryDate))
        .ToList();

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM