グループ化してセット演算子を適用する。 3

さらに再考。
メソッドチェーンを繋げていくことを考えると、IEnumerable<IGrouping> を受け取って IEnumerable<IGrouping> を返すのが良い。

■グループ化セット演算

public static class LinqExtensions
{
  // グループ化したキーで重複除去
  public static IEnumerable<T> DistinctByKey<T, TKey>(this IEnumerable<IGrouping<TKey, T>> source)
  {
    return source.SelectMany(x => x.Select(y => new { key = x.Key, value = y })).ToLookup(x => x.key, x => x.value).Select(x => x.First());
  }

  // グループ化したキーで和
  public static IEnumerable<IGrouping<TKey, T>> GroupUnion<T, TKey>(this IEnumerable<IGrouping<TKey, T>> g1, IEnumerable<IGrouping<TKey, T>> g2)
  {
    var unionedKeys = g1.Select(x => x.Key).Union(g2.Select(x => x.Key));
    return g1.Union(g2).Where(x => unionedKeys.Contains(x.Key));
  }

  // グループ化したキーで積
  public static IEnumerable<IGrouping<TKey, T>> GroupIntersect<T, TKey>(this IEnumerable<IGrouping<TKey, T>> g1, IEnumerable<IGrouping<TKey, T>> g2, bool onlyFirstSource = false)
  {
    var intersectedKeys = g1.Select(x => x.Key).Intersect(g2.Select(x => x.Key));
    var srcGroup = onlyFirstSource ? g1 : g1.Union(g2);
    return srcGroup.Where(x => intersectedKeys.Contains(x.Key));
  }

  // グループ化したキーで差
  public static IEnumerable<IGrouping<TKey, T>> GroupExcept<T, TKey>(this IEnumerable<IGrouping<TKey, T>> g1, IEnumerable<IGrouping<TKey, T>> g2)
  {
    var exceptedKeys = g1.Select(x => x.Key).Except(g2.Select(x => x.Key));
    return g1.Where(x => exceptedKeys.Contains(x.Key));
  }
}

■使い方

// a, b, c のシーケンスがある
var ag = a.GroupBy(x => x.Item);
var bg = b.GroupBy(x => x.Item);
var cg = c.GroupBy(x => x.Item);
var dest = ag.GroupExcept(bg).GroupExcept(cg).DistinctByKey();