简体   繁体   中英

Is it more efficient to perform a LINQ in a foreach statement?

Do these statements do the same exact thing?

var listA = someList.TakeWhile(predicate);
foreach(var item in listA)
{
    /// perform code here
}

versus...

foreach(var item in someList.TakeWhile(predicate))
{
    /// perform some code here
}

Is the collection created first and then iterated through O(N^2)? Or is the collection iterated through as its being created O(N)?

@Jeremy Lakeman provided the right answer in comments.

The type of the variable listA in:

var listA = someList.TakeWhile(predicate);

is IEnumerable<T> , T being the type of an individual element of your collection someList . This is clearly shown by the signature of the TakeWhile method:

public static System.Collections.Generic.IEnumerable<TSource> TakeWhile<TSource> (this System.Collections.Generic.IEnumerable<TSource> source, Func<TSource,int,bool> predicate);

as can be seen at the TakeWhile documentation page .

Declaring a variable of type IEnumerable<T> doesn't enumerate it. To enumerate an IEnumerable , you have to do it explicitly, by enumerating it if a foreach loop for instance, or by using it to produce a new materialized collection, such as a List , Dictionary , etc... by calling methods such .ToList() or ToDictionary() , etc...

This is explicitly stated in the (for instance) ToList documentation :

The ToList<TSource>(IEnumerable<TSource>) method forces immediate query evaluation and returns a List<T> that contains the query results. You can append this method to your query in order to obtain a cached copy of the query results. ToArray has similar behavior but returns an array instead of a List<T> .

So in both your code examples, the IEnumerable you construct will be enumerated only once in the foreach loop.

Also: even if you had materialized your collection before enumerating it:

var listA = someList
    .TakeWhile(predicate)
    .ToList(); // Notice the .ToList() call that forces the enumeration.

foreach(var item in listA)
{
    /// perform code here
}

It would still be an O(n) operation, not an O(n^2). If you take N elements from your someList collection, you will enumerate them once with the .ToList() call, and once in the foreach loop, for a total of 2 x N, not N^2.

Both forms are same. According to Microsoft documentation the query ( TakeWhile ) won't execute until its GetEnumerator method is called directly or by foreach.

The query represented by this method is not executed until the object is enumerated either by calling its GetEnumerator method directly or by using foreach in Visual C# or For Each in Visual Basic.

source

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM