LINQ Features In .NET 6.0

LINQ is a program that was introduced as part of the .NET framework version 3.5 in 2007. LINQ allows developers to write efficient C# code using arrow functions to query collections of objects or from databases using libraries like Entity Framework.

In this tutorial, we are going to discuss top new LINQ features introduced in .NET 6.0.

  1. New methods MaxBy and MinBy
  2. New method Chunk
  3. Index and Range parameters
  4. New method TryGetNonEnumeratedCount
  5. Zip supports three IEnumerables.

MaxBy and MinBy

Assume we have the below collection:

using LINQIndotNET6.MinByAndMaxBy;
var siblings = new List < Siblings > () {
    new Siblings("Praveen", 45),
        new Siblings("Prashanth", 32),
        new Siblings("Pramod", 28)
};

I need to find the youngest and oldest person from this list. How this can be achieved?

Old Approach

using LINQIndotNET6.MinByAndMaxBy;
var siblings = new List < Siblings > () {
    new Siblings("Praveen", 45),
        new Siblings("Prashanth", 32),
        new Siblings("Pramod", 28)
};
// Old version Approach
var youngest = siblings.OrderBy(x => x.Age).First();
var Oldest = siblings.OrderByDescending(x => x.Age).First();
Console.WriteLine($ "Youngest Brother - Name: {youngest.Name} - Age :{youngest.Age}");
Console.WriteLine($ "Oldest Brother - Name: {Oldest.Name} - Age :{Oldest.Age}");
Console.ReadLine();

New Approach

using LINQIndotNET6.MinByAndMaxBy;
var siblings = new List < Siblings > () {
    new Siblings("Praveen", 45),
        new Siblings("Prashanth", 32),
        new Siblings("Pramod", 28)
};
//New Approach
var youngestNew = siblings.MinBy(x => x.Age);
var OldestNew = siblings.MaxBy(x => x.Age);
Console.WriteLine("New Approach");
Console.WriteLine($ "Youngest Brother - Name: {youngestNew?.Name} - Age :{youngestNew?.Age}");
Console.WriteLine($ "Oldest Brother - Name: {OldestNew?.Name} - Age :{OldestNew?.Age}");
Console.ReadLine();

Chunk

Assume that I have the below list of names.

var names = new[] {"Paul","Peter","Michael","George","Mike","Buck"};

I need to split this into multiple lists, such as:

Paul, Peter, Michael

George, Mike, Buck

Old Approach

var names = new [] {
    "Paul",
    "Peter",
    "Michael",
    "George",
    "Mike",
    "Buck"
};
var chunkList = ChunkBy(names, 3).ToList();
var i = 1;
chunkList.ForEach(x => {
    var item = string.Empty;
    x.ToList().ForEach(chunk => {
        item += chunk + ",";
    });
    Console.WriteLine($ "chunk-{i} - {item}");
    i += 1;
});
IEnumerable < IEnumerable < T >> ChunkBy < T > (IEnumerable < T > source, int chunkSize) {
    return source.Select((x, i) => new {
        Index = i, Value = x
    }).GroupBy(x => x.Index / chunkSize).Select(x => x.Select(y => y.Value));
}

Note
If you know anything better than the old approach, please feel free to add it in the comments section.

We have written multiple lines of code to split the list into different chunks. This was simplified in .NET 6.0 through the introduction of a new extension method called Chunk.

New Approach

var names = new [] {
    "Paul",
    "Peter",
    "Michael",
    "George",
    "Mike",
    "Buck"
};
var chunkList = names.Chunk(3).ToList();
var i = 1;
chunkList.ForEach(x => {
    var item = string.Empty;
    x.ToList().ForEach(chunk => {
        item += chunk + ",";
    });
    Console.WriteLine($ "chunk-{i} - {item}");
    i += 1;
});

TryGetNonEnumeratedCount

Assume that we have the below code:

var firstCity = new [] {
    "Brampton"
};
var secondCity = new [] {
    "Mississauga"
};
var thirdCity = new [] {
    "Oakville"
};
//Concatenate these three
IEnumerable < string > cities = firstCity.Concat(secondCity).Concat(thirdCity);

I need to count the number of cities from cities variable. How this can be achieved?

Old Approach

In order to calculate the number of cities, we need to use the extension method Count() on the cities variable. When invoking the Count() method, it will loop through each element. This can be a performance issue, especially when dealing with large collections.

var firstCity = new [] {
    "Brampton"
};
var secondCity = new [] {
    "Mississauga"
};
var thirdCity = new [] {
    "Oakville"
};
//Concatenate these three
IEnumerable <string> cities = firstCity.Concat(secondCity).Concat(thirdCity);
//Old Approach
var count = cities.Count();
Console.WriteLine($ " Number of cities(Old Approach) :  {count}");

New Approach

In .NET 6.0, a new extension method has been introduced that will return a true or false depending whether the count can be returned without iterating the list of items. The actual count is provided in the out variable.

var firstCity = new [] {
    "Brampton"
};
var secondCity = new [] {
    "Mississauga"
};
var thirdCity = new [] {
    "Oakville"
};
//Concatenate these three
IEnumerable < string > cities = firstCity.Concat(secondCity).Concat(thirdCity);
//New Approach
if (cities.TryGetNonEnumeratedCount(out int cityCount)) {
    Console.WriteLine($ " Number of cities(New Approach) :  {cityCount}");
}

Zip

Previously, the LINQ supported Zip method would allow us to enumerate through two collections in parallel. This helped developers to avoid creating additional anonymous or named types to loop through several collections. However, there are scenarios where we may need to iterate through three collections together. Refer to the Microsoft document for more information.

string[] Names = {
    "Buck",
    "Micheal",
    "Marco",
    "Andrei"
};
string[] Designation = {
    "Manager",
    "Consultant",
    "Developer",
    "Lead"
};
int[] EmployeeNumbers = {
    1234,
    5678,
    9101,
    1121
};
var zips = Names.Zip(Designation, EmployeeNumbers);

The zips will have the combination of these three collections. Please find the below screenshot for the output:

Range parameters

Assume we have the below collection:

string[] Names = { "Buck", "Micheal", "Marco", "Andrei","Ken","Paul"};

I want to slice this list to show only Marco and Andrei. How this can be achieved?

Old Approach

string[] Names = {
    "Buck",
    "Micheal",
    "Marco",
    "Andrei",
    "Ken",
    "Paul"
};
//old approach
var nameSublist = Names.Skip(2).Take(2);

The output will be as below:

New Approach

string[] Names = {
    "Buck",
    "Micheal",
    "Marco",
    "Andrei",
    "Ken",
    "Paul"
};
//new approach
var nameSublist = Names.Take(2. .4);

Here we have mentioned the range inside the Take() method. The output will be the same.

Please refer to the Microsoft document for more details.

In this, we have reviewed five new LINQ improvements in .NET 6.0. There are a few more improvements as well, such as:

  • New FirstOrDefault, SingleOrDefault, and LastOrDefault
  • Index Support for ElementAt
  • DistinctBy/UnionBy/IntersectBy/ExceptBy

Please review the Microsoft blog to understand all these features.

Thank you for reading this article. Please leave your comments in the comment box below.