public interface IMerge<out T> { IEnumerable<IMergeMatched<T>> Matched(); IEnumerable<IMergeMatched<T>> Matched(Func<T, T, bool> predicate); IEnumerable<T> NotMatchedBySource(); IEnumerable<T> NotMatchedBySource(Func<T, bool> predicate); IEnumerable<T> NotMatchedByTarget(); IEnumerable<T> NotMatchedByTarget(Func<T, bool> predicate); } public interface IMergeMatched<out T> { T Source { get; } T Target { get; } } public static class Enumerable { public static IMerge<TSource> Merge<TSource>(this IEnumerable<TSource> source, IEnumerable<TSource> target, Func<TSource, TSource, bool> predicate) { return new Merge<TSource>(source, target, predicate); } } public class Merge<T> : IMerge<T> { private readonly Func<T, T, bool> _predicate; private readonly IEnumerable<T> _source; private readonly IEnumerable<T> _target; private IEnumerable<IMergeMatched<T>> _matcheds; private IEnumerable<T> _notMatchedBySource; private IEnumerable<T> _notMatchedByTarget; public Merge(IEnumerable<T> source, IEnumerable<T> taget, Func<T, T, bool> predicate) { _source = source; _target = taget; _predicate = predicate; } public IEnumerable<IMergeMatched<T>> Matched() { if (_matcheds == null) { Analize(); } return _matcheds; } public IEnumerable<IMergeMatched<T>> Matched(Func<T, T, bool> predicate) { return Matched() .Where(t => predicate.Invoke(t.Source, t.Target)) .ToArray(); } public IEnumerable<T> NotMatchedBySource() { if (_notMatchedBySource == null) { Analize(); } return _notMatchedBySource; } public IEnumerable<T> NotMatchedBySource(Func<T, bool> predicate) { return NotMatchedBySource() .Where(predicate) .ToArray(); } public IEnumerable<T> NotMatchedByTarget() { if (_notMatchedByTarget == null) { Analize(); } return _notMatchedByTarget; } public IEnumerable<T> NotMatchedByTarget(Func<T, bool> predicate) { return NotMatchedByTarget() .Where(predicate) .ToArray(); } private void Analize() { var macheds = new List<MergeMached<T>>(); var notMachedBySource = new List<T>(_source); var notMachedByTarget = new List<T>(_target); foreach (var source in _source) { foreach (var target in _target) { var macth = _predicate.Invoke(source, target); if (!macth) continue; macheds.Add(new MergeMached<T>(source, target)); notMachedBySource.Remove(source); notMachedByTarget.Remove(target); } } _matcheds = macheds.ToArray(); _notMatchedBySource = notMachedBySource.ToArray(); _notMatchedByTarget = notMachedByTarget.ToArray(); } } public class MergeMached<T> : IMergeMatched<T> { public MergeMached(T source, T target) { Source = source; Target = target; } public T Source { get; private set; } public T Target { get; private set; } }
How to use?
var source = new List<MediaFolder> { new MediaFolder { Id = "Id1", Name = "Name1", Path = "Path1" }, new MediaFolder { Id = "Id2", Name = "Name2", Path = "Path2" }, new MediaFolder { Id = "Id3", Name = "Name3", Path = "Path3" }, new MediaFolder { Id = "Id4", Name = "Name4", Path = "Path4" }, new MediaFolder { Id = "Id5", Name = "Name5", Path = "Path5" }, new MediaFolder { Id = "Id6", Name = "Name6", Path = "Path6" } }; var target = new List<MediaFolder> { new MediaFolder { Id = "Id1", Name = "Actualizado en el objeto", Path = "Path1" }, //Id2 eliminado new MediaFolder { Id = "Id3", Name = "Name3", Path = "Actualizado tambien" }, new MediaFolder { Id = "Id4", Name = "Name4", Path = "Path4" }, new MediaFolder { Id = "Id5", Name = "Name5", Path = "Path5" }, new MediaFolder { Id = "Id6", Name = "Name6", Path = "Path6" }, new MediaFolder { Id = "Id7", Name = "Nuevo Item 7", Path = "Nuevo Item 7" } }; var merge = source.Merge(target, (x, y) => x.Id == y.Id); var toUpdate = merge.Matched((x, y) => x.Name != y.Name | x.Path != y.Path) .ToArray(); var toDelete = merge.NotMatchedBySource(); var toInsert = merge.NotMatchedByTarget(); Assert.AreEqual(2, toUpdate.Count()); Assert.IsTrue(toUpdate.Count(x => x.Source.Id == "Id1" & x.Target.Id == "Id1") > 0); Assert.IsTrue(toUpdate.Count(x => x.Source.Id == "Id3" & x.Target.Id == "Id3") > 0); Assert.AreEqual("Id7", toInsert.First().Id); Assert.AreEqual("Id2", toDelete.First().Id);