亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

優化具有多個條件的嵌套 where 子句的最佳方法是什么?

優化具有多個條件的嵌套 where 子句的最佳方法是什么?

C#
陪伴而非守候 2023-04-29 16:35:41
ReturnItems我正在嘗試查找退回的單個商品的數量超過該商品的原始訂購數量的列表。所以這里有 2 個不同的對象列表 -IEnumerable<ReturnItem>和IEnumerable<OrderItem>. 問題在于,根據進行退貨的來源(我們的工作流程中有多個地方可以進行退貨),給ItemNumber定的 on aReturnItem可能為空。在這種情況下,我們需要依靠 來ReturnItem.OrderItemId將它與OrderItem.我已經使用 LINQ 解決了這個問題,但它需要一個嵌套的 for 循環(在引擎蓋下)所以我試圖盡可能避免這種情況同時保持可讀性。換句話說,我想避免 O(N ^2) 并尋找 O(N) 或更好但又一次,同時保持可讀性(我知道我在這里要求很多但我想我會看看是否有人有創造性的解決方案)。我創建了一個解決方案,其中我有兩個用于訂單項的字典。其中一個,鍵是項目編號,另一個鍵是訂單項目 ID。這有效并解決了性能問題,但我完全失去了可讀性。這是我的原始 LINQ 語句:// ItemsForReturn = IEnumerable<ReturnItem>// OrderItems = IEnumerable<OrderItem>var invalidQuantityItems = message.ItemsForReturn.Where(returnItem =>{    var matchingOrderItemQuantity = message.OrderItems        .Where(orderItem => orderItem.ItemNumber.Equals(returnItem.ItemNumber) || orderItem.OrderItemId == returnItem.OrderItemId)        .Sum(orderItem => orderItem.Quantity);    return matchingOrderItemQuantity < returnItem.Quantity;});以及上面使用的變量的相應類型:public class ReturnItem{    public int OrderItemId {get; set;}    public string ItemNumber {get; set;}    public int Quantity {get; set;}    // There's more properties but these are the ones that matter{public class OrderItem{    public int OrderItemId {get; set;}    public string ItemNumber {get; set;}    public int Quantity {get; set;}    // There's more properties but these are the ones that matter{我希望這var invalidQuantityItems將是一個IEnumerable<ReturnItems>其單個項目的數量大于訂購的數量(即他們試圖返回比他們首先訂購的更多)。
查看完整描述

3 回答

?
幕布斯7119047

TA貢獻1794條經驗 獲得超8個贊

小修正 - 當前實現的時間復雜度是 O(N*M),你能得到的最好的是 O(N+M)。


問題是如何有效地關聯這兩個集合。在 LINQ 中,這是通過連接實現的,對于這種一對多類型的關聯 -組連接。標準的等價物||將是兩個組連接(匹配集)結果的聯合。


談到可讀性、LINQ 和連接,最好的方法是使用 LINQ查詢語法(有些人也稱它為理解語法是有原因的)。


所以有問題的查詢可以有效地(并且希望可讀)重寫如下:


var invalidQuantityItems =

    from returnItem in message.ItemsForReturn

    join orderItem in message.OrderItems on returnItem.ItemNumber equals orderItem.ItemNumber

    into matchingOrderItems1

    join orderItem in message.OrderItems on returnItem.OrderItemId equals orderItem.OrderItemId

    into matchingOrderItems2

    let matchingOrderItemQuantity = matchingOrderItems1.Union(matchingOrderItems2)

        .Sum(orderItem => orderItem.Quantity)

    where matchingOrderItemQuantity < returnItem.Quantity

    select returnItem;


查看完整回答
反對 回復 2023-04-29
?
喵喵時光機

TA貢獻1846條經驗 獲得超7個贊

我認為字典方法是最好的方法。


關于可讀性,我認為這應該不會太差:


var quantityByItemNumber = message.OrderItems.

    Where(i => i.ItemNumber != null).

    ToDictionary(

        i => i.ItemNumber,

        i => i.Quantity);


var quantityByOrderItemId = message.OrderItems.ToDictionary(

    i => i.OrderItemId,

    i => i.Quantity);


var invalidQuantityItems = message.ItemsForReturn.Where(returnItem =>

{

    int matchingOrderItemQuantity;

    var isNumberMatch = returnItem.ItemNumber != null) &&

        quantityByItemNumber.TryGetValue(returnItem.ItemNumber, out matchingOrderItemQuantity);


    if (!isNumberMatch)

        quantityByOrderItemId.TryGetValue(returnItem.OrderItemId, out matchingOrderItemQuantity)


    return matchingOrderItemQuantity < returnItem.Quantity;

});

事實上,我認為這更具可讀性,因為它不會錯誤地假裝有不止一個匹配OrderItem,必須對哪些數量求和。


查看完整回答
反對 回復 2023-04-29
?
幕布斯6054654

TA貢獻1876條經驗 獲得超7個贊

就優化多個條件而言:

  1. 始終將最有可能結束評估的條件放在首位(您必須根據現有數據或您對系統的了解來確定這一點)。

  2. 如果一種情況比另一種情況更頻繁地發生的可能性不大,那么我們可以考慮評估本身。例如,如果int比較比比較快string,則將int比較放在第一位。

此外,您的代碼不需要單獨的行來獲取Sum; 你可以用同一個表達式來做:

var invalidQuantityItems = message.ItemsForReturn.Where(returnItem =>

    message.OrderItems

        .Where(orderItem =>

            orderItem.OrderItemId == returnItem.OrderItemId ||

            orderItem.ItemNumber.Equals(returnItem.ItemNumber))

        .Sum(orderItem => orderItem.Quantity) < returnItem.Quantity);


查看完整回答
反對 回復 2023-04-29
  • 3 回答
  • 0 關注
  • 159 瀏覽

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號