Last active
April 2, 2019 19:46
-
-
Save pmunin/2fd26917a46200e1dcb58429717ae449 to your computer and use it in GitHub Desktop.
CompareSets extensions, IEnumerable<T>.CompareToSet, FullOuterJoin extension
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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