Research on linqgroupby
Microsoft added the LINQ technology to. NET 3.5, improved the C # language as a supporting tool, and added new features such as Lambda expressions, extension methods, and anonymous types to support LINQ. Microsoft also proposed to use Declarative Programming, that is, to describe computing rules, rather than describe the computing process.
With the use of the LINQ technology, declarative programming can be well achieved, and the written code is highly expressive and readable, this prevents code in the past or other languages from being filled with a large number of for loops or even multi-layer loops with unclear meanings. Do not underestimate the differences between the for loop and the Where, Select, OrderBy extension methods. You can see that the Code intent is really important without comments. When you see a lot of for loops in Java code, including multi-layer loops without comments, you must take a closer look to understand the role of the Code. I personally think that LINQ is one of the most significant features of C # language that distinguishes it from other languages and is also one of the biggest advantages.
Of course, most mainstream languages now include Lambda expressions, so that they can use techniques similar to LINQ to achieve Declarative Programming. For example, Java adds almost the same Lambda expression syntax as C # in Java 8, and adds Stream API to achieve usage similar to LINQ.
It can be seen that Declarative Programming is a development trend. Since C # is used, it is necessary to use more LINQ, make good use of LINQ, and use the method of using LINQ. Don't write a bunch of for loops!
To make good use of LINQ, you must learn about it, understand its principles, mechanisms, and usage. We recommend LINQPad, a good tool for learning and researching LINQ. The following is on the official website and the official website.
Http://www.linqpad.net/
Using System; using System. collections. generic; using System. linq; using System. text; using System. threading. tasks; namespace LinqResearch {class Program {static void Main (string [] args) {var list = new List <int> {2, 1, 6, 4, 3, 5, 7, 8, 10, 9}; Console. writeLine ("list"); var list1 = list. select (I => {Console. writeLine ("In select {0}", I); return I * I;}); Console. writeLine ("list1"); var list2 = list1.Where (I => {Console. writeLine ("In where> 10 {0}", I); return I> 10 ;}); Console. writeLine ("list2"); var list3 = list2.Where (I => {Console. writeLine ("In where <60 {0}", I); return I <60 ;}); Console. writeLine ("list3"); var list4 = list3.OrderBy (I => {Console. writeLine ("In orderby {0}", I); return I ;}); Console. writeLine ("list4"); var list5 = list4.ToList (); Console. writeLine ("list5"); foreach (var I in list5) {Console. writeLine (I );}}}}
Do not look at the following running results first, think about what is printed, and then look at the results to see if it is the same as you want?
listlist1list2list3list4In select 2In where>10 4In select 1In where>10 1In select 6In where>10 36In where<60 36In select 4In where>10 16In where<60 16In select 3In where>10 9In select 5In where>10 25In where<60 25In select 7In where>10 49In where<60 49In select 8In where>10 64In where<60 64In select 10In where>10 100In where<60 100In select 9In where>10 81In where<60 81In orderby 36In orderby 16In orderby 25In orderby 49list516253649
Why do I print the list to list4 first instead of Lambda?
This is because of the delay Calculation of LINQ, that is, only foreach or ToList is used for real computing. The preceding Select and Where statements only declare the calculation rules, instead of computing.
This is very important. If you do not understand this, you will write the code with bugs. The following program prints 1 and 2, instead of 1.
var a = 2; var list = new List<int> { 1, 2, 3 }; var list1 = list.Where(i => i < a); a = 3; foreach (var i in list1) { Console.WriteLine(i); }
Why is the first output after "select" and "where", then "orderby", instead of "select" and "where", and then "orderby?
In this case, the Select, Where, and other extension methods are optimized when the calculation rules are declared (which may be implemented through the expression tree or other methods internally). It is not silly to follow the original defined rules, it is executed sequentially, but calculated and obtained using an optimization method. Therefore, using LINQ is generally better than writing a lot of original for loops, unless you spend a lot of time optimizing your logic (this is generally not the case ).
We can see that the rows In where <60 are not printed for elements 2 and 1. This shows that the code In the second Where is not executed for these two elements, because the first Where statement fails. After the projection (Select) and filtering (Where) are entered, the sorting (OrderBy) is performed. The computing logic in OrderBy is executed only for the elements left after filtering, which is not a waste at all.
Some of the above programs may be written like this.
var list = new List<int> { 2, 1, 6, 4, 3, 5, 7, 8, 10, 9 }; Console.WriteLine("list"); var list1 = list.Select(i => { Console.WriteLine("In select {0}", i); return i * i; }).ToList(); Console.WriteLine("list1"); var list2 = list1.Where(i => { Console.WriteLine("In where>10 {0}", i); return i > 10; }).ToList(); Console.WriteLine("list2"); var list3 = list2.Where(i => { Console.WriteLine("In where<60 {0}", i); return i < 60; }).ToList(); Console.WriteLine("list3"); var list4 = list3.OrderBy(i => { Console.WriteLine("In orderby {0}", i); return i; }).ToList(); Console.WriteLine("list4"); var list5 = list4.ToList(); Console.WriteLine("list5"); foreach (var i in list5) { Console.WriteLine(i); }
In this way, the output result is,
listIn select 2In select 1In select 6In select 4In select 3In select 5In select 7In select 8In select 10In select 9list1In where>10 4In where>10 1In where>10 36In where>10 16In where>10 9In where>10 25In where>10 49In where>10 64In where>10 100In where>10 81list2In where<60 36In where<60 16In where<60 25In where<60 49In where<60 64In where<60 100In where<60 81list3In orderby 36In orderby 16In orderby 25In orderby 49list4list516253649
Although it can also get the correct results, it is unreasonable. In this way, the computation is executed in every step of writing and put into the set, which will cause great performance loss and will lose the advantage of using LINQ.
It is worth thinking about when to perform real computing. When we increase the number of intermediate sets, the performance will be poor. If we do not do so, we may have to repeat the computing several times, and the performance will be poor. It will be explained below.
If you use the Resharper plug-in, you will be prompted for repeated iterations (there may be multiple repeated computations). This function is very good, so that you can analyze whether there are problems.
Be careful when using Max and Min. aggregation operations such as Max and Min require values to exist in the set. Otherwise, an exception will be thrown. I have encountered several bugs caused by this problem.
When there is a Where filter on the current surface, using Max or Min later is not necessarily safe. The following code throws an exception.
var a = 0; var list = new List<int> { 1, 2, 3 }; var min = list.Where(i => i < a).Min(); Console.WriteLine(min);
If a comes from an external value and has a large logic segment, such a BUG is hard to be found.
There are many solutions. Let's analyze them. One way is to call Any and then use Min. The Code is as follows,
var a = 0; var list = new List<int> { 1, 2, 3 }; var list2 = list.Where(i => i < a); var min = 0; if (list2.Any()) { min = list2.Min(); } Console.WriteLine(min);
Change the code to the following,
var a = 3; var list = new List<int> { 1, 2, 3 }; var list2 = list.Where(i => { Console.WriteLine("In where {0}", i); return i < a; }); var min = 0; if (list2.Any(i => { Console.WriteLine("In any {0}", i); return true; })) { min = list2.Min(); } Console.WriteLine(min);
The printed result is,
In where 1In any 1In where 1In where 2In where 31
This may have little impact on the performance, or it may be large, depending on the number of logic in the where (or other logic above) and the number of elements that do not meet the where condition in front of the set. If Any is determined, the execution will not continue, but some repeated computations will still occur.
The code for the second method is as follows,
var a = 3; var list = new List<int> { 1, 2, 3 }; var list2 = list.Where(i => i < a).ToList(); var min = 0; if (list2.Any()) { min = list2.Min(); } Console.WriteLine(min);
This method does not have the overhead of repeated computing, but it also has the overhead of data import set. It is worth considering which performance is higher than the first one.
The code for the third method is as follows,
var a = 0; var list = new List<int> { 1, 2, 3 }; var list2 = list.Where(i => i < a); var min = 0; try { min = list2.Min(); } catch (Exception) { } Console.WriteLine(min);
If an exception is directly eaten and the data volume is large, this method may have the highest performance when the previous filtering condition calculation is complex.
In short, C # developers, learn LINQ well, and make good use of LINQ, you will find it really nice!