DEV Community

loading...
Cover image for .NET 6 LINQ New Features

.NET 6 LINQ New Features

Satish Yadav
・4 min read

What is .NET 6 and why should I care?

.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.

New LINQ Features

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:

  • New methods MaxBy and MinBy
  • New methods Chunk
  • New methods DistinctBy, UnionBy, IntersectBy, and ExceptBy
  • Index and Range parameters
  • New method TryGetNonEnumeratedCount
  • Default parameters for FirstOrDefault, LastOrDefault, and SingleOrDefault
  • Zip supports 3 IEnumerables

New methods MaxBy and MinBy

Finding out maximum or minimum has been easier than even with these new MaxBy or MinBy methods.

Suppose a List of Persons 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},
};
Enter fullscreen mode Exit fullscreen mode

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}");
Enter fullscreen mode Exit fullscreen mode

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}");
Enter fullscreen mode Exit fullscreen mode

Neat, right? Let me know in the comments, if you have alternate methods of getting maximum and minimum using LINQ.

New method Chunk

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
Enter fullscreen mode Exit fullscreen mode

New methods DistinctBy, UnionBy, IntersectBy, and ExceptBy

Exisiting set methods 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
Enter fullscreen mode Exit fullscreen mode

Let me know in the comments, the usage of DistinctBy and ExceptBy.

Index and Range parameters

Range: .., and Index: ^ already exist in C#8, .NET 6 brings these two to LINQ.

  • The ElementAt operator now takes indices from the end.
Person secondLastPerson = people.ElementAt(^2);
//Manish
Enter fullscreen mode Exit fullscreen mode
  • 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

Enter fullscreen mode Exit fullscreen mode

New method TryGetNonEnumeratedCount

Sometimes you need to get a count without the enumeration. 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);
Enter fullscreen mode Exit fullscreen mode

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.

Default parameters for FirstOrDefault, LastOrDefault, and SingleOrDefault

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
Enter fullscreen mode Exit fullscreen mode

This reminds me of ISNULL function of SQL Server.

Zip supports 3 IEnumerables

Before .NET 6, Zip used to take only 2 parameters. Now it takes 3 parameters:

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);
Enter fullscreen mode Exit fullscreen mode

Conclusion

.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.

Next Steps

Originally published at my blog at: https://blog.satishyadav.com/.net-6-linq-new-features

Discussion (0)