Skip to content

Instantly share code, notes, and snippets.

@pmunin
Last active April 2, 2019 19:46
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save pmunin/2fd26917a46200e1dcb58429717ae449 to your computer and use it in GitHub Desktop.
Save pmunin/2fd26917a46200e1dcb58429717ae449 to your computer and use it in GitHub Desktop.
CompareSets extensions, IEnumerable<T>.CompareToSet, FullOuterJoin extension
using System;
using System.Collections.Generic;
using System.Linq;
namespace CompareSetsExtensions
{
public static class CompareSetsExtensions
{
public static IEnumerable<TResult> FullOuterJoin<TLeft, TRight, TKey, TResult>(
IEnumerable<TLeft> left,
IEnumerable<TRight> right,
Func<TLeft,TKey> getKeyLeft,
Func<TRight, TKey> getKeyRight,
Func<(TKey key,TLeft left,TRight right, bool hasLeft, bool hasRight), TResult> getResult,
IEqualityComparer<TKey> cmpByKey=null)
{
var lookup = left.Select(i=>(key:getKeyLeft(i), hasLeft:true, hasRight:false, left:i, right:default(TRight)))
.Concat(
right.Select(i=>(key:getKeyRight(i), hasLeft:false, hasRight:true, left:default(TLeft), right:i))
)
.ToLookup(i=>i.key, i=>i, cmpByKey)
;
foreach (var kvp in lookup)
{
var l = kvp.SingleOrDefault(i=>i.hasLeft);
var r = kvp.SingleOrDefault(i=>i.hasRight);
yield return getResult((kvp.Key, l.left, r.right, l.hasLeft, r.hasRight));
}
}
public static IEnumerable<TResult> FullOuterJoin<T, TKey, TResult>(
IEnumerable<T> left,
IEnumerable<T> right,
Func<T,TKey> getKey,
Func<(TKey key,T left,T right, bool hasLeft, bool hasRight), TResult> getResult,
IEqualityComparer<TKey> cmpByKey=null
)
{
return FullOuterJoin<T, T, TKey, TResult>(left, right, getKey, getKey, getResult, cmpByKey);
}
public static IEnumerable<TResult> FullOuterJoin<T, TResult>(
IEnumerable<T> left,
IEnumerable<T> right,
Func<(T left, T right, bool hasLeft, bool hasRight), TResult> resultSelector,
IEqualityComparer<T> keyComparer=null)
{
return FullOuterJoin<T, T, TResult>(
left,
right,
i=>i,
r=>resultSelector((r.left, r.right, r.hasLeft, r.hasRight)),
keyComparer);
}
public static void CompareToSet<T>(
this IEnumerable<T> oldItems,
IEnumerable<T> newItems,
Action<T> onAddedItem,
Action<T> onRemovedItem,
Action<T, T> onExistInBothItem = null,
IEqualityComparer<T> comparer = null
)
{
var fullJoin = FullOuterJoin(oldItems, newItems, j=>j, comparer);
foreach (var fj in fullJoin)
{
if(fj.hasLeft && fj.hasRight)
onExistInBothItem?.Invoke(fj.left, fj.right);
else if(fj.hasLeft)
onRemovedItem?.Invoke(fj.left);
else if(fj.hasRight)
onAddedItem?.Invoke(fj.right);
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment