Pruebe con esta extensión LINQ
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; }
}
Impementation :
var source = new List<CustomObject>
{
new CustomObject
{
Year = 2010,
Month = 6,
Value = 2
},
new CustomObject
{
Year = 2010,
Month = 7,
Value = 5
},
new CustomObject
{
Year = 2010,
Month = 10,
Value = 3
}
};
var target = new List<CustomObject>
{
new CustomObject
{
Year = 2010,
Month = 7,
Value = 2
},
new CustomObject
{
Year = 2010,
Month = 8,
Value = 1
},
new CustomObject
{
Year = 2010,
Month = 10,
Value = 2
}
};
var merge = source.Merge(target, (x, y) => x.Year == y.Year && x.Month == y.Month);
var toUpdate = merge.Matched((x, y) => x.Value != y.Value)
.ToArray();
var inSourceButNotInTarget = merge.NotMatchedBySource();
var inTargetButNotInSource = merge.NotMatchedByTarget();
Console.WriteLine("Objects to Update");
foreach (var mergeMatched in toUpdate)
{
Console.WriteLine("Source[{0} -{1} - {2} - {3}]",
mergeMatched.Source.Year,
mergeMatched.Source.Month,
mergeMatched.Source.Value,
mergeMatched.Target.Value);
}
Console.WriteLine("In source but not in target");
foreach (var customObject in inSourceButNotInTarget)
{
Console.WriteLine("Source[{0} -{1} - {2} - 0]",
customObject.Year,
customObject.Month,
customObject.Value);
}
Console.WriteLine("In target but not in source");
foreach (var customObject in inTargetButNotInSource)
{
Console.WriteLine("Source[{0} -{1} - 0 - {2}]",
customObject.Year,
customObject.Month,
customObject.Value);
}
Resultado:
objetos para Actualización
2010 -7 - 5 - 2
2010 -10 - 3 - 2
En la fuente, pero no en destino
2010 -6 - 2 - 0. En
objetivo pero no en origen
2010 -8 - 0 - 1
En espera, puede que esto no funcione, ya que excluye los elementos que no tienen una coincidencia en su otra colección. – user7116
Gracias por su sugerencia, pero esta solución no tiene en cuenta los valores en List2 sin contraparte en List1: en mi ejemplo, 2010 - 8 - 1 en List2 se perderá. – Joss57
@ Joss57: llegué a esa conclusión justo cuando publicabas ese comentario, parece. He actualizado mi muestra para usar una unión externa completa. – user7116