Skip to content

Instantly share code, notes, and snippets.

@joshkel
Created August 8, 2018 03:23
Show Gist options
  • Save joshkel/303a2d89c8112d6dca0f07f3b64a6543 to your computer and use it in GitHub Desktop.
Save joshkel/303a2d89c8112d6dca0f07f3b64a6543 to your computer and use it in GitHub Desktop.
LeftJoin using a generator
// Based on https://gist.github.com/reidev275/f765c506aea0e3e3432da591b2c30c15#file-leftJoin-cs
public struct Join<A, B>
{
public A First { get; set; }
public B Second { get; set; }
}
public static IEnumerable<Join<A, B>> LeftJoin2<A, B, C>(this IEnumerable<A> from, IEnumerable<B> join,
Func<A, C> onFrom, Func<B, C> onJoin) where C : IComparable<C>
{
var fromS = from.OrderBy(onFrom);
using (var fromE = fromS.GetEnumerator())
{
if (!fromE.MoveNext())
{
yield break;
}
var joinS = join.OrderBy(onJoin);
using (var joinE = joinS.GetEnumerator())
{
if (!joinE.MoveNext())
{
do
{
yield return new Join<A, B> {First = fromE.Current, Second = default(B)};
} while (fromE.MoveNext());
yield break;
}
var match = false;
while (true)
{
var key = onFrom(fromE.Current);
var b = onJoin(joinE.Current);
var comp = key.CompareTo(b);
switch (comp)
{
case -1:
if (!match) yield return new Join<A, B> {First = fromE.Current, Second = default(B)};
if (!fromE.MoveNext())
{
yield break;
}
match = false;
break;
case 1:
if (!joinE.MoveNext())
{
while (fromE.MoveNext())
{
yield return new Join<A, B> {First = fromE.Current, Second = default(B)};
}
yield break;
}
match = false;
break;
default:
yield return new Join<A, B> {First = fromE.Current, Second = joinE.Current};
match = true;
if (!joinE.MoveNext())
{
while (fromE.MoveNext())
{
yield return new Join<A, B> {First = fromE.Current, Second = default(B)};
}
yield break;
}
break;
}
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment