Skip to content

Instantly share code, notes, and snippets.

@g4s8
Created May 10, 2016 14:52
Show Gist options
  • Save g4s8/9a63d637e4e5e36207da7dbcf287eb9c to your computer and use it in GitHub Desktop.
Save g4s8/9a63d637e4e5e36207da7dbcf287eb9c to your computer and use it in GitHub Desktop.
using System;
using System.Collections.Generic;
using System.Linq;
namespace ConsoleApplication10 {
public static class CollectionsMerge {
private interface IMergeNode<T> {
T Resolve(Func<T, T, T> onConflict);
}
private sealed class NodeConflicted<T> : IMergeNode<T> {
private readonly T _left;
private readonly T _right;
public NodeConflicted(T left, T right) {
_left = left;
_right = right;
}
public T Resolve(Func<T, T, T> onConflict) {
return onConflict(_left, _right);
}
}
private sealed class NodeSimple<T> : IMergeNode<T> {
private readonly T _single;
public NodeSimple(T single) {
_single = single;
}
public T Resolve(Func<T, T, T> onConflict) {
return _single;
}
}
public static IEnumerable<T> MergeWith<T, TKey>(
this IEnumerable<T> self,
IEnumerable<T> other,
Func<T, TKey> uniqueKeySelector,
Func<T, T, T> onConflict
) where TKey : IEquatable<TKey> {
var d1 = self.ToDictionary(i => uniqueKeySelector(i), i => i);
var d2 = other.ToDictionary(i => uniqueKeySelector(i), i => i);
List<IMergeNode<T>> merge = new List<IMergeNode<T>>();
foreach (var entry in d1) {
T same;
if (d2.TryGetValue(entry.Key, out same)) {
merge.Add(new NodeConflicted<T>(entry.Value, same));
d2.Remove(entry.Key);
} else {
merge.Add(new NodeSimple<T>(entry.Value));
}
}
foreach (var entry in d2) {
merge.Add(new NodeSimple<T>(entry.Value));
}
return merge.Select(node => node.Resolve(onConflict));
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment