4

この拡張メソッドを実装して、異なるタイプのコレクションを別のコレクションから同期します。

public static void Synchronize<TFirst, TSecond>(
    this ICollection<TFirst> first,
    IEnumerable<TSecond> second,
    Func<TFirst, TSecond, bool> match,
    Func<TSecond, TFirst> create)
{
    var secondCollection = second.ToArray();

    var toAdd = secondCollection.Where(item => !first.Any(x => match(x, item))).Select(create);

    foreach (var item in toAdd)
    {
        first.Add(item);
    }

    var toRemove = first.Where(item => !secondCollection.Any(x => match(item, x))).ToArray();

    foreach (var item in toRemove)
    {
        first.Remove(item);
    }
}

ReSharper は 2 つの「暗黙的にキャプチャされたクロージャー」を提供します。1 つは最初の場所で、もう 1 つは 2 番目の場所です。見つかりません。

[アップデート]

Eric の観察に基づいて、代わりにハッシュを使用して、equals 関数を使用するバージョンよりも高速なバージョンを作成しました。

public static void Synchronize<TFirst, TSecond>(
    this ICollection<TFirst> first,
    IEnumerable<TSecond> second,
    Func<TSecond, TFirst> convert,
    Func<TFirst, int> firstHash = null,
    Func<TSecond, int> secondHash = null)
{
    if (firstHash == null)
    {
        firstHash = x => x.GetHashCode();
    }

    if (secondHash == null)
    {
        secondHash = x => x.GetHashCode();
    }

    var firstCollection = first.ToDictionary(x => firstHash(x), x => x);
    var secondCollection = second.ToDictionary(x => secondHash(x), x => x);

    var toAdd = secondCollection.Where(item => firstCollection.All(x => x.Key != item.Key)).Select(x => convert(x.Value));

    foreach (var item in toAdd)
    {
        first.Add(item);
    }

    var toRemove = firstCollection.Where(item => secondCollection.All(x => x.Key != item.Key));

    foreach (var item in toRemove)
    {
        first.Remove(item.Value);
    }
}
4

2 に答える 2