IEnumerable.Count() O(n)

发布于 2024-12-19 12:54:22 字数 886 浏览 0 评论 0原文

我刚刚偶然发现了这段代码,我想知道为什么在循环期间完成计数。

  /// <summary>
  /// find the first index in a sequence to satisfy a condition
  /// </summary>
  /// <typeparam name="T">type of elements in source</typeparam>
  /// <param name="source">sequence of items</param>
  /// <param name="predicate">condition of item to find</param>
  /// <returns>the first index found, or -1 if not found</returns>
  public static int FindIndex<T>(this IEnumerable<T> source, Predicate<T> predicate)
  {
         for (int i = 0; i < source.Count(); i++)
         {
               if (predicate(source.ElementAt(i))) return i;
         }
         return -1; // Not found
  }

如果计数可以改变,我们不应该这样做: for (int i = source.Count() - 1; i >= 0; i--)

否则,我认为我们应该在之前计算计数循环开始,而不是每次都开始。

这样做的正确方法是什么?

I just stumbled upon this fragment of code, I was wondering why the Count is done during the loop.

  /// <summary>
  /// find the first index in a sequence to satisfy a condition
  /// </summary>
  /// <typeparam name="T">type of elements in source</typeparam>
  /// <param name="source">sequence of items</param>
  /// <param name="predicate">condition of item to find</param>
  /// <returns>the first index found, or -1 if not found</returns>
  public static int FindIndex<T>(this IEnumerable<T> source, Predicate<T> predicate)
  {
         for (int i = 0; i < source.Count(); i++)
         {
               if (predicate(source.ElementAt(i))) return i;
         }
         return -1; // Not found
  }

If the count can change, shouldn’t we just do it like this instead: for (int i = source.Count() - 1; i >= 0; i--)

Otherwise, I think we should calculate the count before the looping starts, instead of every time.

What would be the correct way to do this?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

感性不性感 2024-12-26 12:54:22

为此编写手动代码的正确方法是丢掉所有垃圾并简单地使用 foreach 进行迭代:

public static int FindIndex<T>(this IEnumerable<T> source, Predicate<T> predicate) 
{
    var index = 0;
    foreach(var item in source) {
        if(predicate(item)) {
            return index;
        }
        ++index;
    }

    return -1;
} 

The correct way to write manual code for this would be to lose all that rubbish and simply iterate with foreach:

public static int FindIndex<T>(this IEnumerable<T> source, Predicate<T> predicate) 
{
    var index = 0;
    foreach(var item in source) {
        if(predicate(item)) {
            return index;
        }
        ++index;
    }

    return -1;
} 
柠檬色的秋千 2024-12-26 12:54:22

这是真正糟糕的代码,可能 - 它可能会迭代所有 O (n^2) 的内容,因为 Count() 可能需要迭代(如果它没有实现 ICollection) -of-T/IList-of-T 提供 .Count(已测试),并且 ElementAt(x) 可能需要迭代 x 个项目,因为它可能没有用于索引器的 IList-of-T。它可能适用于列表/数组,但在一般情况下它提供了糟糕的性能。最坏的情况是它迭代所有 n 项 n 次(对于 Count()s),加上伸缩/三角形系列,给出另一个 n(n+1)/2 增量(对于 ElementAt()s)。

只需使用 foreach 即可。或者更好的是,查找现有的 IndexOf 方法。

That is really bad code, potentially - it could be iterating everything O (n^2), since Count() might need to iterate (if it doesn't implement ICollection-of-T/IList-of-T to offer .Count, which is tested), and ElementAt(x) might need to iterate x items, since it might not have IList-of-T for the indexer. It might work ok for lists/arrays, but in the general case it offers terrible performance. The worst case is that it iterates all n items n times (for the Count()s), plus the telescoping/triangular series, giving another n(n+1)/2 increments (for the ElementAt()s).

Just use foreach. Or better, look for an existing IndexOf method.

雪花飘飘的天空 2024-12-26 12:54:22

如果您打算使用 LINQ,那么为什么不在 LINQ 中完成这一切呢? LINQ 被设计为在这种情况下特别易于使用。

If your going to use LINQ, then why not do it all in LINQ? LINQ was designed to be especially easy to use in situations like this.

一腔孤↑勇 2024-12-26 12:54:22

这是使用 Linq 执行此操作的 O(n) 方法:

public static int FindIndex<T>(this IEnumerable<T> source, Predicate<T> pred)
{
    var foundItem = 
        items
            .Select( (i,index) => new {i,index} )
            .FirstOrDefault( x => pred(x.i));
    return foundItem == null ? -1 : foundItem.index;
}

Here's an O(n) way of doing it with Linq:

public static int FindIndex<T>(this IEnumerable<T> source, Predicate<T> pred)
{
    var foundItem = 
        items
            .Select( (i,index) => new {i,index} )
            .FirstOrDefault( x => pred(x.i));
    return foundItem == null ? -1 : foundItem.index;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文