【问题标题】:Fastest way to assign item from a list to another item in a list将列表中的项目分配给列表中另一个项目的最快方法
【发布时间】:2017-08-25 12:37:48
【问题描述】:

我有两个类,产品和订单,请看类属性一击

public class Product()
{ 
  public int ProductId { get;set; }
  public string ProductName { get;set; }
  public List<Order> OrderList { get;set; }
}

public class Order()
{
  public int OrderId { get;set; }
  public int ProductId { get;set; }
  public string OrderNumber { get;set; }
  public string OrderDescription { get;set; }
}

我有一个单独的调用来从每个类中获取数据

var productList = ProductService.GetAllProductList();
var orderList = OrderService.GetAllOrderList();

我想在这里实现的是我想将订单列表对象分配给产品,我可以通过以下方式实现这一点

  foreach(var product in productList)
  {
     var selectedOrderList = orderList.Where(x => x.ProductId = product.ProductId).ToList();
     product.OrderList = selectedOrderList;
  }

如果我的产品和订单有大量数据,可能会导致一些性能问题。

这是因为我们在 orderList 中进行了不必要的查找,因为已经分配了一些订单数据。

有没有更好的方法来实现这一点?

【问题讨论】:

  • 这真的取决于 productListorderList 实际上是什么 - 从你发布的内容来看,它们可能是任何东西,例如 IQueryables 到数据库等。你 实际上得到了您要解决的性能问题?
  • 你在使用实体框架吗
  • 我没有使用实体框架,我上面使用的服务是从数据库调用的,它返回 List 和 List
  • 您可以同时实现这两种方法并使用秒表来测试哪个更快;)
  • 为了最大限度地减少列表中的查找次数,您可以使用将产品 ID 映射到列表或订单的字典。这样,您只需要遍历一次订单列表即可创建字典。但这并不意味着它总体上会更快。

标签: c# performance linq list


【解决方案1】:

这是因为我们在 orderList 中进行了不必要的查找

我不会称它为不必要,但可以肯定它是低效,因为 LINQ to Objects Where 方法的线性时间复杂度导致 O(N * M) 处理算法的复杂度。

所以你需要一个快速的替代方案,最简单的标准(和非常有效的基于散列的实现)是通过ProductId 使用ToLookup 方法构建和使用Orders lookup,这将减少时间复杂度到 O(N + M):

var ordersByProductId = orderList.ToLookup(order => order.ProductId);
foreach (var product in productList)
     product.OrderList = ordersByProductId[product.ProductId].ToList();

【讨论】:

  • 这真是个好主意
  • 真的很好用,经过测试,性能明显提升。谢谢
  • Inner join 不会比 Look Up 工作得更好,它需要首先创建查找数据结构
  • @MrinalKamboj 基本一样——GroupJoinsource,注意第一行。如果查询正在投影结果,我会使用连接,对于更新,我认为使用显式查找更清晰,更不容易出错 - 使用 LINQ 查询,人们很容易忘记通过枚举它来执行它:)
  • 感谢 Ivan 详细解释
【解决方案2】:

如果您已经从 orderList 中的服务返回所有订单的列表...那么从内存中的列表执行 linq WHERE 应该不会有任何性能问题。

或者您在返回之前更改服务以填充 product.OrderList。

【讨论】:

  • Where子句会延迟执行WhereListIterator,需要再次转换回List或相关数据结构,因此内存转换是最后的操作
  • 但是 .ToList 会确保它不会被延迟,对吧?
  • Where 子句是发布 ToList,然后是另一个 ToList,据我所知,产品和订单列表已经分配在内存中,这是双重打击
猜你喜欢
  • 1970-01-01
  • 2010-11-23
  • 2021-11-23
  • 2019-08-20
  • 1970-01-01
  • 2011-01-05
  • 1970-01-01
  • 1970-01-01
  • 2017-09-28
相关资源
最近更新 更多