Does LINQ try to solve the problem in one pass?

Let's say that list.Where(p=>p.Number > n).Select(p=> p.Name).Where(n=> n.StartsWith(a)).ToList(); Will one pass algorithm be executed or will there be 3 passes?

+6
source share
2 answers

It will create a list in a single pass due to LINQ transferring data.

For example, take this:

 var query = list.Where(p => p.Number > n); 

This in itself does not look at any of the elements of the list. Instead, it remembers the list you are looking at, and when you start iterating over query , each time you request the next item, it will check the list items in turn until it finds a match, and then stop. For instance:

 using (var iterator = query.GetEnumerator()) { iterator.MoveNext(); // This will look for the first match Console.WriteLine(iterator.Current); iterator.MoveNext(); // This will continue from just after the first match } 

Each of the operations works like this - by the time you get:

 var query = list.Where(...) .Select(...) .Where(...); 

... when you request the first element inside the query , it will cling back (so the last Where will request the result of Select , which will request the result of the first Where , which asks for the list) and keep going until you get the result. Then, when you request the next item, it will request a Select result for the next item, etc.

ToList creates a List<T> from all the elements in its source, right away - it is impatient in this sense (and not other operators here that are lazy). But the original list will still be repeated only once.

For more information on how LINQ to Objects works, including an example implementation, you can read my Edulinq blog series .

+6
source

list will be repeated only once in this code, not 3 times.

Of course, if you want to test if any arbitrary request repeats the source code several times, just check it experimentally, just create an IEnumerable that throws an exception when you try to repeat it several times:

 public static IEnumerable<T> ThereCanBeOnlyOne<T>(this IEnumerable<T> source) { return new SingleEnumerable<T>(source); } private class SingleEnumerable<T> : IEnumerable<T> { private bool hasRun = false; private IEnumerable<T> wrapped; public SingleEnumerable(IEnumerable<T> wrapped) { this.wrapped = wrapped; } public IEnumerator<T> GetEnumerator() { if (hasRun) throw new InvalidOperationException( "Sequence cannot be enumerated multilpe times"); else { hasRun = true; return wrapped.GetEnumerator(); } } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } } 

Now you can simply write:

 list.ThereCanBeOnlyOne() .Where(p=>p.Number > n) .Select(p=> p.Name) .Where(n=> n.StartsWith(a)) .ToList(); 

If the code throws an exception, you tried to rename the main list several times. If not, you did not.

+8
source

Source: https://habr.com/ru/post/974559/


All Articles