【问题标题】:Check if IEnumerable has ANY rows without enumerating over the entire list检查 IEnumerable 是否有任何行而不枚举整个列表
【发布时间】:2013-06-04 10:29:21
【问题描述】:

我有以下方法,它返回T 类型的IEnumerable。方法的实现并不重要,除了yield return延迟加载IEnumerable。这是必要的,因为结果可能包含数百万个项目。

public IEnumerable<T> Parse()
{
    foreach(...)
    {
        yield return parsedObject;
    }
}

问题:

我有以下属性可用于确定IEnumerable 是否有任何项目:

public bool HasItems
{
    get
    {
        return Parse().Take(1).SingleOrDefault() != null;
    }
}

是否有更好的方法来做到这一点?

【问题讨论】:

标签: c# .net linq lazy-loading ienumerable


【解决方案1】:

如果序列中有任何元素,IEnumerable.Any() 将返回true,如果序列中没有元素,则返回false。此方法不会迭代整个序列(最多只有一个元素),因为如果它超过第一个元素,它将返回 true,否则返回 false。

【讨论】:

  • 这是不正确的。它确实开始迭代可枚举,但它不会迭代整个事物。
  • @davenewza 这是一种 linq 方法。实现如下:pastebin.com/Acq7WL0E
  • @BraveNewMath 在 LinqPad 中为我工作 if(!Addresses.Any()) { Addresses.Dump(); }
  • 请注意,这可能会导致一些意想不到的影响。例如,如果您首先检查 enumerable.Any() 然后进入 foreach 枚举您的可枚举,由于 Any() 的工作方式,您将丢失该可枚举的第一个元素 - 它已经调用了 e.MoveNext () 一次。
  • 不,这是不正确的。 Any 将执行 MoveNext,但不会修改集合,并且后续 foreach 将从第一项(索引 = 0)开始。这很容易让您测试自己!
【解决方案2】:

类似于Howto: Count the items from a IEnumerable<T> without iterating?Enumerable 意味着是一个惰性、向前读的“列表”,并且像量子力学一样,调查它的行为会改变它的状态。

查看确认:https://dotnetfiddle.net/GPMVXH

    var sideeffect = 0;
    var enumerable = Enumerable.Range(1, 10).Select(i => {
        // show how many times it happens
        sideeffect++;
        return i;
    });

    // will 'enumerate' one item!
    if(enumerable.Any()) Console.WriteLine("There are items in the list; sideeffect={0}", sideeffect);

enumerable.Any() 是检查列表中是否有任何项目的最简洁方法。您可以尝试投射到不懒惰的东西,例如if(null != (list = enumerable as ICollection&lt;T&gt;) &amp;&amp; list.Any()) return true

或者,您的方案可能允许使用Enumerator 并在枚举之前进行初步检查:

var e = enumerable.GetEnumerator();
// check first
if(!e.MoveNext()) return;
// do some stuff, then enumerate the list
do {
    actOn(e.Current);  // do stuff with the current item
} while(e.MoveNext()); // stop when we don't have anything else

【讨论】:

  • 并用枚举器更新小提琴表明初步检查,同时仍然评估可枚举的 1 次(即sideeffect++)不会导致 extra 枚举:@ 987654323@
  • 注意使用 Any(Func predicate) 会产生“副作用”sharplab.io/#gist:60dd304540eee9eec3effb59ec1bb94d
  • @NathanSmiechowski 是的,这就是我的示例/小提琴要展示的内容——每次调用 .Any(with or w/o a predicate) 时,sideeffect 都会增加一次,因为它必须从列表中枚举至少一项。
【解决方案3】:

回答这个问题并消除所有疑问的最佳方法是查看“Any”函数的作用。

   public static bool Any<TSource>(this IEnumerable<TSource> source) {
        if (source == null) throw Error.ArgumentNull("source");
        using (IEnumerator<TSource> e = source.GetEnumerator()) {
            if (e.MoveNext()) return true;
        }
        return false;
    }

https://github.com/microsoft/referencesource/blob/master/System.Core/System/Linq/Enumerable.cs

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-08-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多