Related Readings
C# Use LINQ query operator instance code (I)
C# uses LINQ query operator instance code (II)
6. Concatenated table operator
1. Internal connection
1. Use the join clause to merge two data sources according to specific conditions, but before you need to get two lists to connect.
Business Description: Return information on driver’s championship and team championships from 1958 to 1965, related to year
var racers = from r in () from y in select new { Year = y, Name = + " " + }; var teams = from t in () from y in select new { Year = y, Name = }; var racersAndTeams0 = (from r in racers join t in teams on equals orderby select new { Year = , Racer = , Team = }).Take(10);
Method syntax:
var racersAndTeams = racers .Join(teams, r => , t => , (r, t) => new { Year = , Racer = , Team = }) .OrderBy(p => ).Take(10);
result:
Year Champion Constructor Title
1958: Mike Hawthorn Vanwall
1959: Jack Brabham Cooper
1960: Jack Brabham Cooper
1961: Phil Hill Ferrari
1962: Graham Hill BRM
1963: Jim Clark Lotus
1964: John Surtees Ferrari
1965: Jim Clark Lotus
1966: Jack Brabham Brabham
1967: Denny Hulme Brabham
2. Or merge into a LINQ query
var racersAndTeams = (from r in from r1 in () from yr in select new { Year = yr, Name = + " " + } join t in from t1 in () from yt in select new { Year = yt, Name = } on equals orderby select new { Year = , Racer = , Team = }).Take(10);
Method syntax
var racersAndTeams0 = () .SelectMany(m => , (m, y) => new { Racer = m, Year = y }) .Join(() .SelectMany(m => , (m, y) => new { Team = m, Year = y }) , m => , m1 => , (m, m1) => new { Year = , Racer = + " " + , Team = }) .OrderBy(m => ).Take(10);
2. Left outer connection (DefaultIfEmpty)
The left outer join returns all elements in the left sequence, even if they do not match the elements in the right sequence.
Use the join clause andDefaultIfEmptyMethod definition. Use DefaultIfEmpty to define the default value to its right.
linq only supports left connection. If you want to connect right, change query and query1 to the location
Business description: If a racer sets a championship earlier than the team, there may be only a racer championship in a certain year without a team championship. At this time, you need to connect the left to query.
var racers = from r in () from y in select new { Year = y, Name = + " " + }; var teams = from t in () from y in select new { Year = y, Name = }; var racersAndTeams = (from r in racers join t in teams on equals into rt from t in () orderby select new { Year = , Champion = , Constructor = t == null ? "no constructor championship" : }).Take(10); foreach (var item in racersAndTeams) { ("{0}: {1,-20} {2}", , , ); }
result
1950: Nino Farina no constructor championship
1951: Juan Manuel Fangio no constructor championship
1952: Alberto Ascari no constructor championship
1953: Alberto Ascari no constructor championship
1954: Juan Manuel Fangio no constructor championship
1955: Juan Manuel Fangio no constructor championship
1956: Juan Manuel Fangio no constructor championship
1957: Juan Manuel Fangio no constructor championship
1958: Mike Hawthorn Vanwall
1959: Jack Brabham Cooper
3. Group connection
The left outer join uses group joins and into clauses. It has some of the same as group connections, except that the DefaultIfEmpty method does not apply.
When using group connections, two elements of two independent sequences are associated based on equal keys and grouped the results.
It is often used to return the form of "primary key object-foreign key object collection".
Business Description: Return driver championship and team championship information from 1958 to 1965, related and grouped according to year
Note: The into keyword that appears directly after the join clause will be translated as GroupJoin, and the into keyword after the select or group clause means that a query will continue.
// Query expressionvar racersAndTeams =( from r in racers join t in teams on equals into groupTeams select new { Year = , Racer = , GroupTeams = groupTeams }).Take(10);
Method syntax:
var racersAndTeams1 = racers .GroupJoin(teams, r => , t => , (r, t) => new { Year = , Racer = , GroupTeams = t } ).Take(10);; foreach (var item in racersAndTeams) { ("{0}: {1,-20} {2}", , , ()); }
result:
1950: Nino Farina 0
1952: Alberto Ascari 0
1953: Alberto Ascari 0
1951: Juan Manuel Fangio 0
1954: Juan Manuel Fangio 0
1955: Juan Manuel Fangio 0
1956: Juan Manuel Fangio 0
1957: Juan Manuel Fangio 0
1958: Mike Hawthorn 1
1961: Phil Hill 1
2. Join…on…equals…supportMultiple key associations, you can use anonymous types to join multiple key values, as shown below:
// Query expressionvar query17 = from r in racers join r2 in teams on new { Name = (0, 1), Year = } equals new { Name = (0, 1), Year = } into yearResults select new { Results = yearResults }; foreach (var item in query17) { foreach (var info in ) { (); } } //McLaren
7. Collection operation
Collection operations compare objects by calling the GetHashCode() and Equals() methods of the entity class. For custom comparisons, objects that implement the IEqualityComparer interface can be passed.
- 1) Union: union, return the union of two sequences, and remove duplicate elements.
- 2) Concat: Connect, return the union of two sequences.
- 3) Intersect: Intersection, returns the elements that are in both sequences, that is, intersection.
- 4) Except: Difference set, returns elements that only appear in one sequence, that is, the difference set.
Business Notes: Get the list of drivers with both the "Ferrari" and the "Mclaren"
void Main() { Func<string, IEnumerable<Racer>> racersByCar = car => from r in () from c in where c == car orderby select r; foreach (var racer in racersByCar("Ferrari").Intersect(racersByCar("McLaren"), new RacerComparer())) { (racer); } } public class RacerComparer : IEqualityComparer<Racer> { public bool Equals(Racer x, Racer y) { if ((x, y)) return true; return x != null && y != null && == && == ; } public int GetHashCode(Racer obj) { int hashStudentId = (); int hashScore = (); return hashStudentId ^ hashScore; } }
result:
Niki Lauda
- 5) Zip: By using the specified delegate function to merge two sequences, the total number of sets remains unchanged.
Example: Merge html start tag and end tag
var letters = new string[] { "A", "B", "C", "D", "E" }; var numbers = new int[] { 1, 2, 3 }; var q = (numbers, (l, n) => l + ()); foreach (var s in q) (s);
result:
A1
B2
C3
- 6) SequenceEqual: To determine whether the two sequences are equal, the content and order are required to be equal.
Example:
int[] arr1 = { 1, 4, 7, 9 }; int[] arr2 = { 1, 7, 9, 4 }; ("Before sorting Is it equal or not:{0}" , (arr2) ? "yes" : "no"); // no(); ("After sorting Is it equal or not:{0}" , ((k => k)) ? "yes" : "no"); // yes
8. Partition operator
Partition operations such as extension methods Take() and Skip() can be used for paging.
Added at the "last" of the query,Returns a subset of the collection.
1、Take():
Returns a specified number of consecutive elements from the beginning of the sequence.
2、TakeWhile():
As long as the specified condition is met, the element of the sequence will be returned.
Starting from the first element, read the list of people with Starts less than 40, and stop returning immediately whenever an element with Starts greater than 40 is encountered.
var racers = (from r in () orderby select r ) <strong>.TakeWhile(p </strong><strong>=> < 40</strong><strong>);</strong> foreach (var name in racers) { ($"{name:A}"); }
result:
Alberto Ascari, Italy; starts: 32, wins: 10
Nino Farina, Italy; starts: 33, wins: 5
3、Skip():
Skip the specified number of elements in the sequence and return the remaining elements.
Business Description: Paginate the driver championship list by 5 names per page.
int pageSize = 5; int numberPages = (int)(().Count() / (double)pageSize); for (int page = 0; page < numberPages; page++) { ("Page {0}", page); var racers = ( from r in () orderby select + " " + ) .Skip(page * pageSize).Take(pageSize); foreach (var name in racers) { (name); } }
result:
Page 0
Fernando Alonso
Mario Andretti
Alberto Ascari
Jack Brabham
Jim Clark
Page 1
Juan Manuel Fangio
Nino Farina
Emerson Fittipaldi
Mika Hakkinen
Mike Hawthorn
4、SkipWhile():
As long as the specified criteria are met, the elements in the sequence are skipped and the remaining elements are returned.
9. Aggregation operator
The aggregate operator returns a value.
1. LongCount: Returns a System.Int64, indicating the total number of elements in the sequence.
Business Description: The following Count method only returns racers who have won more than three championships. Because the same count needs to be used more than once in the same query, a variable is defined using the let clause.numberYear.
var query = from r in () let numberYears = () where numberYears >= 3 orderby numberYears descending, select new { Name = + " " + , TimesChampion = numberYears }; foreach (var r in query) { ("{0} {1}", , ); } //Michael Schumacher 7 //Juan Manuel Fangio 5 //Alain Prost 4 //Jack Brabham 3 //Niki Lauda 3 //Nelson Piquet 3 //Ayrton Senna 3 //Jackie Stewart 3
2. Sum: The sum of all numbers in the sequence.
Business Description: The following Sum method is used to calculate the total number of times a country wins a game.
First, group the racers according to the country, and then in the newly created anonymous type, the Wins attribute is assigned to a country's total number of times they have won the race.
var countries = (from c in from r in () group r by into c select new { Country = , Wins = (from r1 in c select ).Sum() } orderby descending, select c).Take(5); foreach (var country in countries) { ("{0} {1}", , ); } //UK 138 //Germany 91 //Brazil 78 //France 51 //Finland 40
3. Aggregate: Pass a lambda expression that aggregates all values.
Business Description: Aggregate
The first parameter is the seed of the algorithm, i.e.Initial value. (Optional)
The second parameter is an expression, used toCalculate each element(The first parameter of the delegation isAccumulated variables, the second parameterCurrent item)。
The third parameter is an expression, used toConvert data to the final result。
int[] numbers = { 1, 2, 3 }; int y = ((tol, n) => prod + n); // 1+2+3 = 6 int x = (0, (tol, n) => tol + n); // 0+1+2+3 = 6 int z = (0, (tol, n) => tol + n, r => r * 2);// (0+1+2+3)*2 = 12
10. Conversion operator
Query can be postponed until accessing data items. When using a query in iteration, the query is executed.
Using the conversion operator will immediately execute the query and place the query results in an array, list or dictionary.
LINQ itself supports four different collection generation methods, including the generation of arrays.ToArray()
, generate listToList
, generate dictionary collectionToDictionary
And generateLookup<tkey,telement>
ClassicToLookup
。
1) Cast:
Converts non-generic IEnumerable collection elements to the specified generic type, and throws an exception if the type conversion fails.
If needed on a non-typed collection (e.g.ArrayList
) Use LINQ query to use the Cast method.
In the following example, basedObject
Type ofArrayList
The collection is filled with Racer objects.
var list = new ArrayList(() as ); var query = from r in () where == "USA" orderby descending select r; foreach (var racer in query) { ("{0:A}", racer); } //Mario Andretti, USA; starts: 128, wins: 12 //Phil Hill, USA; starts: 48, wins: 3
2) ToArray:
Create an array from IEnumerable.
3) ToList:
Execute the query immediately and create a List from IEnumerable.
4) ToDictionary:
Create a Dictionary<tkey,tvalue> from IEnumerable based on the specified key selector function.
Convert a list to a dictionary:
var spartans = new List<dynamic> { new {Opponent="UAB",Score="55-18"}, new {Opponent="Bowling Green",Score="55-18"}, new {Opponent="Pittsburgh",Score="55-18"}, new {Opponent="Notre Dame",Score="55-18"} }; //Dictionary is a collection of key-value pairs. ToDictionary converts an IEnumerable<T> object (such as the result returned by a LINQ query)//Convert to an IDictionary<Key,Value> object.IDictionary<string, dynamic> stats = (key => (string)); ("Spartans vs. {0} {1}", stats["Notre Dame"].Opponent, stats["Notre Dame"].Score);
5) ToLookup:
Create a , from IEnumerable, based on the specified key selector function.
ToLookup is more complicated to use. Lookup is similar to Dictionary. However, each key of Dictionary only corresponds to one value, while Lookup is a 1:n mapping.
Lookup has no public constructor and is immutable. After creating a Lookup, elements or keys cannot be added or deleted. (ToLookup can be regarded as a combination of GroupBy and ToDictionary)
Business Description: Group driver champions by their use model and display the driver's name using the "williams" model.
ILookup<string, Racer> racers = (from r in () from c in //Use composite from query select new { Car = c, Racer = r } ).ToLookup(cr => , cr => ); if (("Williams")) { foreach (var williamsRacer in racers["Williams"]) { (williamsRacer); } } //Alan Jones //Keke Rosberg //Nelson Piquet //Nigel Mansell //Alain Prost //Damon Hill //Jacques Villeneuve
6) DefaultIfEmpty:
Returns the elements of the specified sequence; if the sequence is empty, a single set of elements containing the default values of the type parameter.
var defaultArrCount = (new int[0]).DefaultIfEmpty().Count(); (defaultArrCount); //1
7) AsEnumerable:
The return type is IEnumerable . Used to handle collaboration between LINQ to Entities operating remote data sources and local collections
11. Generate operators
The generator operator returns a new collection. The three generation operators are not extension methods, but normal static methods that return sequences.
1) Empty:
Generates an empty sequence of IEnumerable with the specified type parameters.
The Empty() method returns an iterator that does not return a value, which is used for parameters that require a collection, and can pass an empty collection to the parameters.
string[] names1 = { "Hartono, Tommy" }; string[] names2 = { "Adams, Terry", "Andersen, Henriette Thaulow", "Hedlund, Magnus", "Ito, Shu" }; string[] names3 = { "Solanki, Ajay", "Hoeing, Helge", "Andersen, Henriette Thaulow", "Potra, Cristina", "Iallo, Lucio" }; List<string[]> namesList = new List<string[]> { names1, names2, names3 }; IEnumerable<string> allNames = (<string>(), (current, next) => > 3 ? (next) : current); foreach (string name in allNames) { (name); } //Adams, Terry //Andersen, Henriette Thaulow //Hedlund, Magnus //Ito, Shu //Solanki, Ajay //Hoeing, Helge //Potra, Cristina //Iallo, Lucio
2) Range:
Generates a sequence of integers in the specified range IEnumerable.
If you need to fill in a range of numbers with one or two, you should use the Range() method at this time. The first parameter of this method isStart value, take the second parameter asNumber of items to be filled。
var values = (1, 20); foreach (var value in values) { (value); } // result 1 2 3 4 5 6 ...... 19 20
The Range() method does not return a set of values filled with the defined. Like other methods, it delays the query and returns a RangeEnumerator. The yield return statement is used to increment the value. This result can also be used with other extension methods.
var values = (1, 5).Select(n => n * 3); foreach (var value in values) { (value); } // 3 6 9 12 15
3) Repeat:
Generate a sequence containing a duplicate value IEnumerable.
Repeat() method returns an iterator that repeats the same value for a specific number of times.
IEnumerable<string> strings = ("I like programming.", 3); foreach (String str in strings) { (str); } //I like programming. //I like programming. //I like programming.
12. Quantifier operator
If the element sequence meets the specified conditions, the quantifier operator returns a Boolean value.
1) Any:
Determines whether the sequence contains any elements; or determines whether any elements in the sequence satisfy the conditions.
//Get if there is a driver champion named "Schumacher"var hasRacer_Schumacher = ().Any(r => == "Schumacher"); (hasRacer_Schumacher); //True
2) All:
Determines whether all elements in the sequence meet the conditions.
3) Contains:
Determines whether the sequence contains the specified element.
13. Element operator
These element operators return only one element, not an IEnumerable. (Default value: the value type defaults to 0, and the reference type defaults to null)
Business Description: Get the third-ranked driver championship
var Racer3 = () .OrderByDescending(r => ) .ElementAtOrDefault(2); (Racer3); //Ayrton Senna
- 1) First: Returns the first element in the sequence; if it is an empty sequence, this method will throw an exception.
- 2) FirstOrDefault: Returns the first element in the sequence; if it is an empty sequence, it returns the default value default(TSource).
- 3) Last: Returns the last element of the sequence; if it is an empty sequence, this method will throw an exception.
- 4) LastOrDefault: Returns the last element in the sequence; if it is an empty sequence, it returns the default value default(TSource).
- 5) Single: Returns the only element of the sequence; if it is an empty sequence or the sequence contains multiple elements, this method will raise an exception.
- 6) SingleOrDefault: Returns the unique element in the sequence; if it is an empty sequence, it returns the default value default(TSource); if the sequence contains multiple elements, this method will raise an exception.
- 7) ElementAt: Returns the element at the specified index in the sequence, the index starts at 0; if the index is out of range, this method will raise an exception.
- 8) ElementAtOrDefault: Returns the element at the specified index in the sequence, the index starts from 0; if the index is out of range, the default value is returned (TSource).
14. Parallel query, parallel Linq
The AsParallel() method extends the IEnumerable interface and returns the ParallelQuery class, so normal collection classes can be queried in parallel.
var query24 = from r in ().AsParallel() select r;
Fifteen. Partitioner
The AsParallel() method not only extends the IEnumerable interface, but also extends the Partitioner class. Through it, the partitions created can be affected.
Create a partitioner manually
var query25 = from r in ((), true).AsParallel() select r;
16. Cancel
.NET provides a standard method to cancel long-running tasks, and also works with parallel Linq.
To cancel a long-running query, add the WithCancellation() method to the query and pass a CancellactionToken as a parameter.
The CancelllationToken token is created from the CancellactionTokenSource class. The query runs in a separate thread where an exception of type OperationCanceledException is caught. If the query is cancelled, this exception will be triggered.
In the main thread, calling the CancellationTokenSource class Cancel() method can cancel the task.
CancellationTokenSource cts = new CancellationTokenSource(); (() => { try { var res = from r in ().AsParallel().WithCancellation() select r; ("query finished, sum:{0}", res); } catch (OperationCanceledException ex) { ("canceled!"); (); } }); string input = (); if (().Equals("y")) { (); ("canceled 2!"); }
This is all about this article about C# using LINQ query operators. I hope it will be helpful to everyone's learning and I hope everyone will support me more.