Is a takewhile() checked every iteration using som

2019-09-21 00:07发布

问题:

for instance, let's say I want to do something like this:

bool foo(List<strings> stringList, int counter)//assume this list has, like, 10 elements, and counter=3, idk
{
    bool found= false;
    for(int i=0; i<stringlist.Count && !found; i++)
    {
        if(stringlist[i].length < 2 || counter >=6)
            found=true;
        counter++;
    }
    return found
}

Now, Is that equivelent to this:

bool foo(List<strings> stringList, int counter)//assume this list has, like, 10 elements, and counter=3, idk
{
    bool found= false;
    foreach(string s in stringlist.Takewhile(x=> (!found)))
    {
        if(s.length < 2 || counter >=6)
            found=true;
        counter++;
    }
    return found
}

Does this second example behave like the first, or does it always skip the whole loop? As a follow up, if I still want to use a foreach, do I really have to use a break to get around this? Also, sorry if I did something dumb in these examples, I am trying to simplify a version of a path-finding algo I am writing and this was the simplest example I could think of to ask this question...

回答1:

As the documentation of Microsoft here :

The TakeWhile(IEnumerable, Func) method tests each element of source by using predicate and yields the element if the result is true. Enumeration stops when the predicate function returns false for an element or when source contains no more elements.

and this is the decompiled TakeWhile() method :

public static IEnumerable<TSource> TakeWhile<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate)
{
  if (source == null)
    throw Error.ArgumentNull(nameof (source));
  if (predicate == null)
    throw Error.ArgumentNull(nameof (predicate));
  return Enumerable.TakeWhileIterator<TSource>(source, predicate);
}

private static IEnumerable<TSource> TakeWhileIterator<TSource>(IEnumerable<TSource> source, Func<TSource, bool> predicate)
{
  foreach (TSource source1 in source)
  {
    if (predicate(source1))
      yield return source1;
    else
      break;
  }
}

as you can see, yes the TakeWhile() method loops through all the elements doing the check and it's internal loop is irrelevant to your outer loop.