Can I use the infinite range and work on it?

Enumerable.Range(0, int.MaxValue) .Select(n => Math.Pow(n, 2)) .Where(squared => squared % 2 != 0) .TakeWhile(squared => squared < 10000).Sum() 

Will this code be repeated for all integer values ​​from 0 to max-range or only through integer values ​​to satisfy take-while, where and select conditions? Can someone clarify?

EDIT: My first attempt to make sure it works as expected was dumb. I cancel it :)

+8
c # linq
source share
3 answers

int.MaxValue + 5 overflows as a negative number. Try it yourself:

 unchecked { int count = int.MaxValue + 5; Console.WriteLine(count); // Prints -2147483644 } 

The second argument to Enumerable.Range must be non-negative - hence the exception.

Of course, you can use infinite sequences in LINQ. Here is an example of such a sequence:

 public IEnumerable<int> InfiniteCounter() { int counter = 0; while (true) { unchecked { yield return counter; counter++; } } } 

It will overflow too, but it will continue ...

Note that some LINQ statements (such as Reverse ) must read all the data before they can give their first result. Others (like Select ) may just save the streaming results when they read them from the input. See My Edulinq Messages for details on the behavior of each statement (in LINQ to Objects).

+11
source share

The way to resolve such issues as a whole is to think about what happens in steps.

Linq turns linq code into something that will be executed by the query provider. It could be something like creating SQL code or anything else. In the case of linq-to-objects, it generates some equivalent .NET code. Thinking that this .NET code will allow us to speculate about what will happen. *

With your code, you have:

 Enumerable.Range(0, int.MaxValue) .Select(n => Math.Pow(n, 2)) .Where(squared => squared % 2 != 0) .TakeWhile(squared => squared < 10000).Sum() 

Enumerable.Range is a bit more complicated than:

 for(int i = start; i != start + count; ++i) yield return i; 

... but that's close enough for an argument.

Choose close enough to:

 foreach(T item in source) yield return func(item); 

Where is close enough to:

 foreach(T item in source) if(func(item)) yield return item; 

TakeWhile is close enough to:

 foreach(T item in source) if(func(item)) yield return item; else yield break; 

The amount is close enough to:

 T tmp = 0;//must be numeric type foreach(T x in source) tmp += x; return tmp; 

This simplifies several optimizations, etc., but close enough to reason. Accepting each of them, your code is equivalent to:

 double ret = 0; // part of equivalent of sum for(int i = 0; i != int.MaxValue; ++i) // equivalent of Range { double j = Math.Pow(i, 2); // equivalent of Select(n => Math.Pow(n, 2)) if(j % 2 != 0) //equivalent of Where(squared => squared %2 != 0) { if(j < 10000) //equivalent of TakeWhile(squared => squared < 10000) { ret += j; //equaivalent of Sum() } else //TakeWhile stopping further iteration { break; } } } return ret; //end of equivalent of Sum() 

Now, in a sense, the code above is simpler and, in a sense, more complicated. The whole point of using LINQ is that it is much easier. However, to answer your question: "Will this code iterate over all integer values ​​from 0 to max-range or simply through integer values ​​to satisfy the take requests, where to select the operators?" we can review the foregoing and see that those that do not satisfy where they are repeated, to find that they do not satisfy where, but no more work is done with them, and as soon as TakeWhile is satisfied, all further work ( break in my correspondence not LINQ).

Of course, only in this case, TakeWhile() means that the call will return within a reasonable amount of time, but we also need to think briefly about others to make sure that they leave when they go. Consider the following version of your code:

 Enumerable.Range(0, int.MaxValue) .Select(n => Math.Pow(n, 2)) .Where(squared => squared % 2 != 0) .ToList() .TakeWhile(squared => squared < 10000).Sum() 
Theoretically, this will give exactly the same answer, but it will take much more time and much more memory (perhaps enough to cause an exception from memory). Here's the equivalent non-linq code:
 List<double> tmpList = new List<double>(); // part of ToList equivalent for(int i = 0; i != int.MaxValue; ++i) // equivalent of Range { double j = Math.Pow(i, 2); // equivalent of Select(n => Math.Pow(n, 2)) if(j % 2 != 0) //equivalent of Where(squared => squared %2 != 0) { tmpList.Add(j);//part of equivalent to ToList() } } double ret = 0; // part of equivalent of sum foreach(double k in tmpList) { if(k < 10000) //equivalent of TakeWhile(squared => squared < 10000) { ret += k; //equaivalent of Sum() } else //TakeWhile stopping further iteration { break; } } return ret; //end of equivalent of Sum() 

Here we see how adding ToList() to the Linq query significantly affects the query, so each element created by the Range() call should be considered. Methods such as ToList() and ToArray() break the chain so that the non-linq equivalents no longer fit "inside" each other, and therefore no one can stop the work of those who came earlier. ( Sum() is another example, but since after your TakeWhile() in your example this is not a problem).

Another thing that will make it go through each iteration of the range is if you have While(x => false) , because it will never run the test in TakeWhile .

* Although there may be further optimizations, esp in the case of SQL code, as well, while conceptually, for example, Count() equivalent to:

 int c = 0; foreach(item in src) ++c; return c; 

For this to turn into a call to the Count property of the ICollection or Length property for the array, it means that O (n) above is replaced with an O (1) (for most ICollection implementations) call, which is a massive gain for large sequences.

+3
source share

Your first code will only iterate until the TakeWhile condition is TakeWhile . It will not be repeated until int.MaxValue .

int.MaxValue + 5 will result in a negative integer. Enumerable.Range throws an ArgumentOutOfRangeException if its second argument is negative. So why you get an exception (before any iteration).

+2
source share

All Articles