【问题标题】:How to optimize this code如何优化这段代码
【发布时间】:2010-03-17 16:16:16
【问题描述】:

它有一个属性: 字符串代码 和其他 10 个。

常用代码是字符串列表(string[]) 汽车汽车列表(汽车[]) filtersListOfCars 是列表。

for (int index = 0; index < cars.Length; index++)
{
    Car car = cars[index];
    if (commonCodes.Contains(car.Code))
    {
         filteredListOfCars.Add(car);
    }
}

很遗憾,这个方法执行的时间太长了。

我有大约 5 万条记录

如何缩短执行时间??

【问题讨论】:

    标签: c# performance


    【解决方案1】:

    最简单的优化是将commonCodes 从string[] 转换为更快的查找结构,例如Dictionary&lt;string,object&gt;HashSet&lt;string&gt;(如果您使用.Net 3.5 或更高版本)。这将减少这个循环的大 O 复杂度,并且根据 commonCodes 的大小应该使这个循环执行得更快。

    【讨论】:

      【解决方案2】:

      Jared 已正确指出您可以使用 HashSet 对其进行优化,但我还想指出整个方法是不必要的,因为输出列表浪费内存并使代码不太清晰。

      你可以把整个方法写成:

      var commonCodesLookup = new HashSet<int>(commonCodes);
      var filteredCars = cars.Where(c => commonCodesLookup.Contains(c.Code));
      

      filteredCars 过滤操作的执行将被推迟,因此如果它的消费者只想要前 10 个元素,即使用 filteredCars.Take(10),那么这不需要构建整个列表(或任何列表)。

      【讨论】:

      • Linq Join 方法为您执行查找逻辑,因此您不必指定 HashSet。 car.Join(commonCodes, car=>car.Code, code => code, (car, code) => car)
      • @DRBlaise:Join确实使用了哈希表,但它也是一个实现细节,依赖于它们可能会发生变化的东西是有风险的(即使变化不太可能)。如果你想保证一定程度的性能,那么你应该明确语义。
      • @phenevo:是的,它是正确的,我只是没有注意到你的问题中你说代码是string[] 并假设它是int[] 的部分。显然T 应该是您的Code 的任何类型(在本例中为string)。
      【解决方案3】:

      为了做你想做的事,我会使用 Linq ToLookup 方法来创建 ILookup,而不是使用字典。 ToLookup 是专门为这种类型的场景制作的。它基本上是对组的索引查找。您想通过Code 对您的汽车进行分组。

      var carCodeLookup = cars.ToLookup(car => car.Code);
      

      carCodeLookup 的创建会很慢,但是您可以使用它来基于Code 快速查找汽车。要获取常用代码列表中的汽车列表,您可以快速查找。

      var filteredCarsQuery = commonCodes.SelectMany(code => carCodeLookup[code]);
      

      这假设您的汽车列表不会经常更改,并且您的 commonCodes 在查询之间是动态的。

      【讨论】:

        【解决方案4】:

        你可以使用 linq join 命令,比如

        var filteredListOfCars = cars.Join(commonCodes, c => c.Code, cC => cC, (car, code) => car).ToArray();
        

        【讨论】:

          【解决方案5】:

          这是 linq 选项的替代方案(这也是个好主意):如果您想快速进行过滤,我建议您利用内置类型。您可以创建一个DataTable,它有两个字段,数组中汽车的 id 和代码(如果它们也很重要,您可以添加其他 10 项)。然后你可以在它周围创建一个DataView 并使用它的 filter 属性。它在内部使用了一些非常快速的索引(我相信是 B 树),因此除非您是算法高手,否则您可能无法手动超越它的性能,如果您是,您就不会在这里问。这取决于您在做什么以及性能的重要性。

          【讨论】:

            【解决方案6】:

            看起来您真正要检查的是“代码”是否常见,而不是汽车。您可以考虑一种飞行重量模式,其中汽车共享 Code 对象的公共实例。然后,代码对象可以具有 IsCommon 属性和 Value 属性。 然后,您可以在公共代码列表更改时更新已使用的代码对象。 现在,当您进行过滤时,您只需要检查每个汽车代码的 IsCommon 属性

            【讨论】:

              猜你喜欢
              • 2013-02-15
              • 2016-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2018-05-02
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多