System.Linq.GroupJoin<TOuter, TInner, TKey, TResult> Method
Performs a correlated inner join between two sequences. In other words, a GroupJoin
is a join that considers all elements from the outer
sequence and for each element in the outer
sequence, it finds all elements in the inner
sequence that match the specified key. It then combines these matching elements into a group for each outer element.
This method is typically used in LINQ to Objects and LINQ to SQL to perform complex joins where one-to-many relationships need to be expressed.
public static IEnumerable<TResult> GroupJoin<TOuter, TInner, TKey, TResult>( this IEnumerable<TOuter> outer, IEnumerable<TInner> inner, Func<TOuter, TKey> outerKeySelector, Func<TInner, TKey> innerKeySelector, Func<TOuter, IEnumerable<TInner>, TResult> resultSelector, [System.Collections.Generic.IEqualityComparer<TKey> comparer = null] )
Parameters
outer
- An
IEnumerable<TOuter>
whose elements are to be joined with the elements of the inner sequence. inner
- An
IEnumerable<TInner>
whose elements to join to the elements of the outer sequence. outerKeySelector
- A function to extract the join key from each element of the outer sequence.
innerKeySelector
- A function to extract the join key from each element of the inner sequence.
resultSelector
- A function to create a result element from an outer element and a group of matching inner elements.
comparer
(Optional)- An
IEqualityComparer<TKey>
to compare keys.
Return Value
IEnumerable<TResult>
- An
IEnumerable<TResult>
that contains elements of typeTResult
that are obtained by performing an inner join on the two sequences.
Remarks
The GroupJoin
method performs a correlated join. This means that for each element in the outer
sequence, it iterates through the inner
sequence to find matching elements based on the provided key selectors.
The resultSelector
function receives the outer element and an IEnumerable<TInner>
containing all matching inner elements. This allows for the creation of results that aggregate or combine related data from both sequences.
If no elements in the inner
sequence match an element in the outer
sequence, the IEnumerable<TInner>
passed to the resultSelector
for that outer element will be empty.
Example
C# Example
using System;
using System.Collections.Generic;
using System.Linq;
public class Department
{
public int Id { get; set; }
public string Name { get; set; }
}
public class Employee
{
public int Id { get; set; }
public string Name { get; set; }
public int DepartmentId { get; set; }
}
public class Program
{
public static void Main(string[] args)
{
var departments = new List<Department>
{
new Department { Id = 1, Name = "Sales" },
new Department { Id = 2, Name = "Marketing" },
new Department { Id = 3, Name = "Engineering" }
};
var employees = new List<Employee>
{
new Employee { Id = 101, Name = "Alice", DepartmentId = 1 },
new Employee { Id = 102, Name = "Bob", DepartmentId = 1 },
new Employee { Id = 201, Name = "Charlie", DepartmentId = 2 },
new Employee { Id = 301, Name = "David", DepartmentId = 3 },
new Employee { Id = 302, Name = "Eve", DepartmentId = 3 }
};
var departmentEmployees = departments.GroupJoin(
employees,
department => department.Id,
employee => employee.DepartmentId,
(department, empGroup) => new
{
DepartmentName = department.Name,
Employees = empGroup.Select(e => e.Name)
}
);
foreach (var deptEmp in departmentEmployees)
{
Console.WriteLine($"Department: {deptEmp.DepartmentName}");
if (deptEmp.Employees.Any())
{
Console.WriteLine(" Employees: " + string.Join(", ", deptEmp.Employees));
}
else
{
Console.WriteLine(" No employees in this department.");
}
}
}
}
Output:
Department: Sales
Employees: Alice, Bob
Department: Marketing
Employees: Charlie
Department: Engineering
Employees: David, Eve