我正在尝试找到ReturnItems
的列表,该列表中退回的单个商品的数量大于该商品的原始订购数量。因此,这里有2个不同的对象列表在起作用-IEnumerable<ReturnItem>
和IEnumerable<OrderItem>
。问题是,取决于进行退货的来源(我们的工作流中有多个地方可以进行退货),给定ItemNumber
上的ReturnItem
可能为空。在这种情况下,我们将需要依靠ReturnItem.OrderItemId
将其与OrderItem
进行匹配。
我已经使用LINQ解决了这个问题,但是它需要一个嵌套的for循环(在幕后),因此我试图避免这种情况,同时还要保持可读性。换句话说,我想避免运行时间为O(N ^ 2)并寻找O(N)或更好,但是在保持可读性的同时(我知道我在这里要求很多,但我想知道是否有人有创意的解决方案)。我创建了一个解决方案,其中针对订单项有两个字典。其中一个,关键是商品编号,另一个关键是订单商品编号。这样可以解决性能问题,但是我完全失去了可读性。
这是我原来的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>
,其单个商品的数量大于所订购的数量(即,他们试图退回的商品比订购的商品多)。 / p>
干杯!
答案 0 :(得分:3)
小校正-当前实现的时间复杂度为O(N * M),而您可以获得的最好结果是O(N + M)。
问题在于如何有效地关联这两个集合。在LINQ中,这是通过joins来实现的,并且对于这种一对多的相关性-group join。相当于a.out
的条件将是两个组联接(匹配集)的结果中的Union。
谈到可读性,LINQ和联接,最好的方法是使用LINQ query 语法(有些人也将其称为 comprehension 语法)。
因此,相关查询可以有效地(并且希望可读)进行如下重写:
LD_RUNPATH_SEARCH_PATHS
答案 1 :(得分:1)
我认为词典方法是最好的选择。
关于可读性,我认为这应该还不错:
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
,必须对这些数量求和。
答案 2 :(得分:0)
就优化多个条件而言:
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);