Let's do some fancy set operations using the new UnionBy()
, IntersectBy()
, ExceptBy()
, and DistinctBy()
methods in .NET 6!
Current Implementation
.NET 5 and below include operations in LINQ that are collectively called set operations; that is, they operate on sets of values compared to other sets of values.
For example, the Union()
method produces the set union by combining all values from two sets, while removing the duplicates.
var numbers1 = new List<int>() {2, 5, 6, 9};
var numbers2 = new List<int>() {5, 8, 10};
var union = numbers1.Union(numbers2);
//2, 5, 6, 9, 8, 10
The Intersect()
method produces the values that appear in both the sets.
var numbers1 = new List<int>() {2, 5, 6, 9};
var numbers2 = new List<int>() {5, 8, 10};
var intersect = numbers1.Intersect(numbers2);
//5
The Except()
method gives the numbers that only appear in the first set, and do not appear in the second set.
var numbers1 = new List<int>() {2, 5, 6, 9};
var numbers2 = new List<int>() {5, 8, 10};
var except = numbers1.Except(numbers2);
//2, 6, 9
Finally, the Distinct()
method operates on a single set and gives the distinct values from within that set.
var numbers = new List<int>() {6, 1, 6, 7, 1, 8, 1, 2, 3, 2};
var distinct = numbers.Distinct();
//7, 8, 3
Just like we saw in the previous post about MaxBy()
and MinBy()
, these kinds of operations are great if you are only working with primitive types. But what if you need to work with complex collections of classes? .NET 6 includes a new set of methods in the LINQ library to help with those situations.
New Implementation
Let's say we have the User
class from the previous post, and two collections of users.
UnionBy
We can use the new UnionBy()
method to do a complex calculation: get users from both sets who have distinct birth years. This calculation "favors" the first set, because if users in the second set have the same birth year as users in the first set, the users from the first set will be included and the users from the second set will not.
IntersectBy
The IntersectBy()
method can be used to find users who do not share a birth year with anyone from the opposite set.
ExceptBy
What if we wanted to find all users in both sets, except those who have particular first names? We can do that using ExceptBy()
.
public void Examples()
{
List<User> users = GetUserList();
var users2 = GetUserList2();
users.AddRange(users2);
var names = new List<string>() { "Hailee", "Jackson", "Jeremy" };
var exceptByFirstName = users.ExceptBy(names, x => x.FirstName);
//Terrance Johnson
//Angelica Johnson
//Toni Berkowitz
//Vanessa Warren
//Lawrence Neilson
}
DistinctBy
Finally, we can do things like "get all users by distinct birth dates" using DistinctBy()
:
Other Considerations
With these methods, order of invocation matters. For example, consider the following code, which is nearly the same as the earlier use of IntersectBy()
with two small changes.
public void Examples()
{
var users = GetUserList();
var users2 = GetUserList2();
var intersectionBirthYear
= users2.IntersectBy(users.Select(x => x.DateOfBirth.Year),
x => x.DateOfBirth.Year);
//Jeremy Yardling
//Toni Berkowitz
//Vanessa Warren
//Lawrence Neilson
}
Because users2
is now the "primary" set, we get a completely different result set than in the earlier example. Be careful with your order of invocation!
Demo Project
As with all posts in this series, there is a demo project you can check out over on GitHub with the examples for UnionBy()
, IntersectBy()
, DistinctBy()
, and ExceptBy()
found in this post. Check it out!
Happy Coding!