.NET Documentation

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 type TResult 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

See Also