【问题标题】:Are queries faster than a for loop when trying to find a nonexistent value in a certain range?在尝试查找某个范围内不存在的值时,查询是否比 for 循环更快?
【发布时间】:2012-02-08 22:54:10
【问题描述】:

我有一个方法应该考虑一个类的实例集合,并找到第一个不作为属性出现在这些实例中的正数。

这是我的情况:我有一个名为 GestorePersonale(员工经理类)的类,它管理 ListDipendente(员工类)实例。每个Dipendente 都有一个ID,该ID 在List 中存在的所有其他Dipendente 实例中必须是唯一的。

当创建一个新的Dipendente 时,我必须找到一个唯一的 ID 来分配给它。
对于这个任务,我首先找出列表中所有实例中的最高 ID (Matricola),然后循环遍历从 0 到该 ID 的所有数字,以尝试找到用于新 @ 的间隙 ID 987654329@。如果一切都失败了,我将分配一个对应于max + 1 的 ID。

这是MatricolaMax() 方法,它负责返回List 中所有实例之间的最高ID (我发布此代码只是为了清楚起见,它不是部分问题的重点是,即使任何关于性能改进的建议也会在这里受到高度赞赏)

private uint MatricolaMax ()
{
    // Looking for the highest ID
    return dipendenti.OrderByDescending( dipendente => dipendente.Matricola ).First().Matricola;
}

这是这个问题的标题所指的方法:

private uint MatricolaLibera ()
{
    var max = MatricolaMax();
    for ( uint i = 0; i < max; i++ )
    {
        var conto = dipendenti.Where( dipendente => dipendente.Matricola == i ).Count();

        if ( conto == 0 )
            return i;
    }
    return max + 1;
}

正如您在上面的代码中看到的,要查找间隙 ID,我使用Where 查询来检查是否存在具有与i 对应的Matricola (ID) 的Dipendente 实例。

如果我使用 for 循环而不是查询来执行此操作,这将是我要编写的代码:

private uint MatricolaLibera ()
{
    var max = MatricolaMax();
    bool found;
    for ( uint i = 0; i < max; i++ )
    {
        found = false;
        for( int j = 0; j < dipendenti.Count; j++)
            if ( dipendenti[j].Matricola == i )
            {
                found = true;
                break;
            }

        if ( !found )
            return i;
    }
    return max + 1;
}

基本上添加一个内部 for 循环和一个布尔检查以查看是否找到了空闲 ID。


我的问题如下:

所介绍的两种方法(查询与内部 for 循环)中哪一种表现最好?是否存在更好的解决方案?

【问题讨论】:

  • 你到底为什么要问我们?你已经写了两种方式。 运行代码,看看哪个更快然后你就会知道答案了!如果你有两匹马,你想知道哪一匹跑得更快,你是在网上问从未见过马的陌生人,还是你跑马
  • 答案可能取决于集合大小。我认为如果你只衡量它们的工作方式会更好。我会投票认为第二个会更快,因为它不会创建新对象。但实际上,我认为这种差异不会有任何显着性。
  • @EricLippert 哈哈哈,这就是缺乏适当睡眠可能带来的后果:P。等一下,我会去试试这个并发布结果。
  • Count() 单独在 IEnmerable 上进行 O(n) 操作

标签: c# linq optimization for-loop


【解决方案1】:

当然,正如 Eric 所说,您应该运行代码来回答您的问题,即哪个性能更好。 (但它应该在与实际使用中看到的尺寸相似的尺寸上运行,而不仅仅是小尺寸。)

我会建议一些事情:

您的 MatricolaMax 方法正在对列表进行排序以找到最高值。排序至少需要 O(n*logn),而简单地枚举列表并比较值将是 O(n)。

MatricolaLibra 的两个函数都会遍历整个集合中的每个可能值。这是 O(n*m)。我建议遍历列表一次,将每个键放入字典中,然后枚举字典以查找第一个不存在的键。这应该快得多。

【讨论】:

    【解决方案2】:

    Eric Lippert 对您的主要问题有最佳答案,但对于您的“有没有更好的方法”问题,这里有一个答案。

    您可以使用整数来保存找到的最高选项,也可以使用布尔数组来保存使用过的值。假设您有一个良好的上限,您可以使用单个数组来执行此操作,如果您不这样做,您将需要根据需要处理数组的增长。然后您可以简单地枚举您的列表,标记使用的值并在需要时更新最大值。如果您不知道上限或者它可以任意高,请使用不同的算法。

    但是此时您正在查看一些非常重要的代码(如果不知道上限,这些代码可能会执行得很糟糕),因此如果您现有的解决方案有效,请使用它们。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-08-16
      • 2018-11-02
      • 1970-01-01
      • 2020-07-27
      • 1970-01-01
      • 1970-01-01
      • 2021-08-26
      • 2017-06-08
      相关资源
      最近更新 更多