I have two collections.
var a = new List<string>() { "a", "b", "c", "d", "e", "f", "j" };
var b = new List<string>() { "a", "c", "d", "h", "i" };
And I would like to do some action on the item in case it’s missing in one collection or another.
public static Synchronize<T>(IEnumerable<T> first, IEnumerable<T> second, Action<T> firstSynchronizer, Action<T> secondSynchronizer)
{
var firstUnique = first.Distinct();
var secondUnique = second.Distinct();
foreach (var item in firstUnique)
{
if (!secondUnique.Contains(item)) firstSynchronizer(item);
}
foreach (var item in second.Distinct())
{
if (!firstUnique.Contains(item)) secondSynchronizer(item);
}
}
This is what I got but I am not happy with it. I can’t help but wonder if there’s a better way to implement this, because I think Distinct() is pretty big performance hit and also I am not sure if it’s better to iterate whole second Enumerable and check if item is not present in first Enumerable already (like above) or if it would be better to iterate second.Except(first)? What do you guys think?
I call it like this:
var a = new List<string>() { "a", "b", "c", "d", "e", "f", "j" };
var b = new List<string>() { "a", "c", "d", "h", "i" };
Synchronize(a.ToArray(), b.ToArray(), t => b.Add(t), t => a.Add(t));
I call ToArray() so collections don’t get changed while being iterated over and lambdas just add missing elements to respective lists.
Also, this is just a test implementation. In production environment, Enumerables won’t be of same type. This is intended to be used to sync remote and local storage. In future, Enumerable first will be for example ICollection<DummyRemoteItem> and Enumerable second will be List<IO.FileSystemInfo>. But I want it to be more generic. To make it possible to work with different collections, I think I would propose another type parameter and a Func<T1, T2, bool> for comparing items. That would be a best approach, right?
Generally, what’s the best way to implement insides of
Synchronize<T>(IEnumerable<T> first,IEnumerable<T> second,Action<T> firstSynchronizer,Action<T> secondSynchronizer)
and
Synchronize<TFirst, TSecond>(IEnumerable<TFirst> first,IEnumerable<TSecond> second,Action<TFirst> firstSynchronizer,Action<TSecond> secondSynchronizer, Func<TFirst, TSecond, bool> predicate)
Linq full outer join is your friend here.
Here’s an implementation (from here)
so:
and look for nulls in the resulting enumerable.