SoFunction
Updated on 2025-03-06

C# uses LINQ query operator instance code (II)

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 =&gt; 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 collectionToDictionaryAnd 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, basedObjectType ofArrayListThe 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&lt;dynamic&gt;
        {
            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&lt;string, dynamic&gt; stats = (key =&gt; (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&lt;string, Racer&gt; racers =
    (from r in ()
     from c in  //Use composite from query     select new
     {
         Car = c,
         Racer = r
     }
     ).ToLookup(cr =&gt; , cr =&gt; );

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 =&gt;  == "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.