CSharp - LINQ GroupJoin

Introduction

GroupJoin operator performs a grouped join on two sequences based on keys extracted from each element in the sequences.

Join operator passes a single outer sequence element with a single matching inner sequence element to the resultSelector method.

In Join operator multiple matching inner sequence elements for a single outer sequence element result in multiple calls to resultSelector for the outer sequence element.

With the GroupJoin operator, all matching inner sequence elements for a specific outer sequence element are passed to resultSelector as a sequence of that type of element, resulting in the resultSelector method being called only once for each outer sequence element.

Prototypes

public static IEnumerable<V> GroupJoin<T, U, K, V>(
  this IEnumerable<T> outer,
  IEnumerable<U> inner,
  Func<T, K> outerKeySelector,
  Func<U, K> innerKeySelector,
  Func<T, IEnumerable<U>, V> resultSelector);

The first argument of the method is named outer therefore the sequence the GroupJoin operator is called on will be referred to as the outer sequence.

GroupJoin operator will return an object that will first enumerate the inner sequence of type U elements, calling the innerKeySelector method once for each element and storing the element.

Then the returned object will enumerate the outer sequence of type T elements.

As the returned object enumerates each outer sequence element, it will call the outerKeySelector method to obtain its key and retrieve the matching inner sequence elements from the hash table using that key.

Exceptions

ArgumentNullException is thrown if any arguments are null.

Demo

using System;
using System.Linq;
using System.Collections;
using System.Collections.Generic;
class Program//  ww  w.j a  va2s  .  c  o  m
{
    static void Main(string[] args)
    {
        Student[] Students = Student.GetStudentsArray();
        StudentOptionEntry[] empOptions = StudentOptionEntry.GetStudentOptionEntries();

        var StudentOptions = Students
          .GroupJoin(
            empOptions,
            e => e.id,
                  o => o.id,
                  (e, os) => new
                  {
                      id = e.id,
                      name = string.Format("{0} {1}", e.firstName, e.lastName),
                      options = os.Sum(o => o.optionsCount)
                  });

        foreach (var item in StudentOptions)
            Console.WriteLine(item);
    }
}
class Student
{
    public int id;
    public string firstName;
    public string lastName;

    public static ArrayList GetStudentsArrayList()
    {
        ArrayList al = new ArrayList();

        al.Add(new Student { id = 1, firstName = "Joe", lastName = "Ruby" });
        al.Add(new Student { id = 2, firstName = "Windows", lastName = "Python" });
        al.Add(new Student { id = 3, firstName = "Application", lastName = "HTML" });
        al.Add(new Student { id = 4, firstName = "David", lastName = "Visual" });
        al.Add(new Student { id = 101, firstName = "Kotlin", lastName = "Fortran" });
        return (al);
    }

    public static Student[] GetStudentsArray()
    {
        return ((Student[])GetStudentsArrayList().ToArray());
    }
}

class StudentOptionEntry
{
    public int id;
    public long optionsCount;
    public DateTime dateAwarded;

    public static StudentOptionEntry[] GetStudentOptionEntries()
    {
        StudentOptionEntry[] empOptions = new StudentOptionEntry[] {
      new StudentOptionEntry {
        id = 1,
        optionsCount = 2,
        dateAwarded = DateTime.Parse("1990/12/31") },
      new StudentOptionEntry {
        id = 2,
        optionsCount = 3000,
        dateAwarded = DateTime.Parse("1992/06/30")  },
      new StudentOptionEntry {
        id = 2,
        optionsCount = 3000,
        dateAwarded = DateTime.Parse("1991/01/01")  },
      new StudentOptionEntry {
        id = 3,
        optionsCount = 5000,
        dateAwarded = DateTime.Parse("1997/09/30") },
      new StudentOptionEntry {
        id = 2,
        optionsCount = 3000,
        dateAwarded = DateTime.Parse("2000/04/01")  },
      new StudentOptionEntry {
        id = 3,
        optionsCount = 7500,
        dateAwarded = DateTime.Parse("1998/09/30") },
      new StudentOptionEntry {
        id = 3,
        optionsCount = 7500,
        dateAwarded = DateTime.Parse("1998/09/30") },
      new StudentOptionEntry {
        id = 4,
        optionsCount = 2456,
        dateAwarded = DateTime.Parse("1997/12/31") },
      new StudentOptionEntry {
        id = 101,
        optionsCount = 2,
        dateAwarded = DateTime.Parse("1998/12/31") }
    };

        return (empOptions);
    }
}

Result