CSharp - LINQ Join

Introduction

The Join operator performs an inner equijoin on two sequences based on keys extracted from each element in the sequences.

Prototypes

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

The first argument of the method is named outer. The sequence we call the Join operator on will be referred to as the outer sequence.

The Join operator will return an object that, when enumerated, will first enumerate the inner sequence of type U elements, calling the innerKeySelector method once for each element and storing the element in a hash table.

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

For each outer sequence element and matching inner sequence element pair, the returned object will call the resultSelector method passing both the outer element and the matching inner element.

The resultSelector method will return an instantiated object of type V, which the returned object will place in the output sequence of type V.

The order of the outer sequence elements will be preserved as well as the order of the inner elements within each outer element.

Exceptions

ArgumentNullException is thrown if any arguments are null.

In the code, we first obtain a couple arrays of data to join using the two common classes.

Because we are calling the Join operator on the Students array, it becomes the outer sequence, and empOptions becomes the inner sequence.

resultSelector is creating an anonymous class as the element type for the resulting output sequence.

Example Code Calling the Join Operator

Demo

using System;
using System.Linq;
using System.Collections;
using System.Collections.Generic;
class Program/*from  w  w w  .j  a va2 s.co m*/
{
    static void Main(string[] args)
    {
        Student[] Students = Student.GetStudentsArray();
        StudentOptionEntry[] empOptions = StudentOptionEntry.GetStudentOptionEntries();

        var StudentOptions = Students
          .Join(
            empOptions,     //  inner sequence
            e => e.id,      //  outerKeySelector
            o => o.id,      //  innerKeySelector
            (e, o) => new   //  resultSelector
            {
                id = e.id,
                name = string.Format("{0} {1}", e.firstName, e.lastName),
                options = 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