24
.NET 6 LINQ New Features
.NET 6
is the upcoming major overhaul for .NET
. It unifies entire .NET
experience. No more .NET Core
, .NET Full Framework
, Xamarin
, Mono
, etc. Just a single .NET
.At the time of writing this post, 5 previews of
.NET 6
have been released and last couple of releases have been blessing for LINQ
.Here are few top new
LINQ
features:MaxBy
and MinBy
Chunk
DistinctBy
, UnionBy
, IntersectBy
, and ExceptBy
Index
and Range
parametersTryGetNonEnumeratedCount
FirstOrDefault
, LastOrDefault
, and SingleOrDefault
Zip
supports 3 IEnumerables
Finding out maximum or minimum has been easier than even with these new
MaxBy
or MinBy
methods.Suppose a
List
of Person
s as:static List<Person> people = new List<Person>
{
new Person { Id = 1, Name = "Amit", Age = 38},
new Person { Id = 2, Name = "Ravi", Age = 36},
new Person { Id = 3, Name = "Manish", Age = 34},
new Person { Id = 4, Name = "Satish", Age = 29},
};
If we need to get maximum and minimum, currently here's how to do it:
//Without using MaxBy and MinBy
Person oldestPerson = people.OrderByDescending(person => person.Age).First();
Person youngestPerson = people.OrderBy(person => person.Age).First();
Console.WriteLine($"Oldest Person without using MaxBy: {oldestPerson.Name}");
Console.WriteLine($"Youngest Person without using MaxBy: {youngestPerson.Name}");
But with
MaxBy
and MinBy
, it's just a single method call:Person oldestPerson = people.MaxBy(person => person.Age);
Person youngestPerson = people.MinBy(person => person.Age);
Console.WriteLine($"Oldest Person using MaxBy: {oldestPerson.Name}");
Console.WriteLine($"Youngest Person using MaxBy: {youngestPerson.Name}");
Neat, right? Let me know in the comments, if you have alternate methods of getting maximum and minimum using
LINQ
.A new method
Chunk
slices the IEnumerable
into provided sizes. e.g. If you have a collection of 4 elements and you need to cluster them into fixed size of 2, here's how to do:IEnumerable<Person[]> cluster = people.Chunk(2);
// Print each cluster.
foreach(var people in cluster)
{
Console.WriteLine($"Cluster of {string.Join(",", people.Select(person => person.Name))}");
}
//Prints
// Cluster of Amit,Ravi
// Cluster of Manish,Satish
Exisiting set methods
e.g.
Distinct
, Union
, Intersect
, and Except
have been powered up by these new methods which can take a selector function to operate.e.g.
IEnumerable<Person> evenAgedPeople = people.Where(person => person.Age % 2 == 0);
//Amit,Ravi,Manish
IEnumerable<Person> personAbove35 = people.Where(person => person.Age > 35);
//Amit,Ravi
IEnumerable<Person> union = evenAgedPeople.UnionBy(personAbove35, x => x.Age);
//Amit,Ravi,Manish
IEnumerable<Person> intersection = evenAgedPeople.IntersectBy(personAbove35.Select(p => p.Age), x => x.Age);
//Amit,Ravi
Let me know in the comments, the usage of
DistinctBy
and ExceptBy
.Range
: ..
, and Index
: ^
already exist in C#
8, .NET 6
brings these two to LINQ
.ElementAt
operator now takes indices from the end.
Person secondLastPerson = people.ElementAt(^2);
//Manish
Skip
and Take
now take Range
as well:
IEnumerable<Person> take3People = people.Take(..3);
//Amit,Ravi,Manish
IEnumerable<Person> skip1Person = people.Take(1..);
//Ravi,Manish,Satish
IEnumerable<Person> take3Skip1People = people.Take(1..3);
//Ravi,Manish
IEnumerable<Person> takeLast2People = people.Take(^2..);
//Manish,Satish
IEnumerable<Person> skipLast3People = people.Take(..^3);
//Amit
IEnumerable<Person> takeLast3SkipLast2 = people.Take(^3..^2);
//Ravi
Sometimes you need to get a count without the enumeration.
Useful in scenarios where you want to get a count but not at the cost of enumerating the
e.g.
TryGetNonEnumeratedCount
will try to get count without forcing an enumeration. It internally checks for the implementation of ICollection
i.e. IEnumerable
that already has a mechanism to get count without forcing an enumeration. Otherwise it'll try to take advantage of new improvements in LINQ
.Useful in scenarios where you want to get a count but not at the cost of enumerating the
IEnumerable
.e.g.
List<Person> anotherList = people.TryGetNonEnumeratedCount(out int count) ? new List<Person>(count): new List<Person>();
anotherList.AddRange(people);
In our case right now, we know that people is just an in-memory list, but what if it was from database of some
Stream
, then it would've made sense to find out the count to optimize the instantiation of anotherList
object by specifying capacity
parameter.Current
FirstOrDefault
, LastOrDefault
, and SingleOrDefault
methods return default(T)
if the source IEnumerable
is empty. The new overloads accept a parameter which will be returned if source is empty.e.g.
List<int> emptyList = new List<int>();
int value = emptyList.FirstOrDefault(-1);
//-1 instead of 0
This reminds me of
ISNULL
function of SQL Server
.IEnumerable<int> ids = Enumerable.Range(1, 4);
IEnumerable<Person> allPeople = people;
IEnumerable<int> allAges = people.Select(person => person.Age);
IEnumerable<(int Id, Person Person, int Age)> zipped = ids.Zip(allPeople, allAges);
.NET 6
previews are bring awesome set of new features with every new release. Let me know in comments which all features you're excited for..NET 6
today and try out.Originally published at my blog at: https://blog.satishyadav.com/.net-6-linq-new-features
24