グループ化してセット演算子を適用する。 4
さらに再考。
ILookupに変換する部分を抽出。これでもうすこし使い勝手が良くなる。
■グループ化セット演算
public static class GroupLinqExtensions { // groupのシーケンスをlookupに変換 public static ILookup<TKey, T> GroupToLookup<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); } // グループ化したキーで重複除去 public static IEnumerable<T> GroupDistinct<T, TKey>(this IEnumerable<IGrouping<TKey, T>> source) { return source.GroupToLookup().Select(x => x.First()); } // グループ化したキーで和 public static IEnumerable<IGrouping<TKey, T>> GroupUnion<T, TKey>(this IEnumerable<IGrouping<TKey, T>> first, IEnumerable<IGrouping<TKey, T>> second) { var unionedKeys = first.Select(x => x.Key).Union(second.Select(x => x.Key)); return first.Union(second).Where(x => unionedKeys.Contains(x.Key)); } // グループ化したキーで積 public static IEnumerable<IGrouping<TKey, T>> GroupIntersect<T, TKey>(this IEnumerable<IGrouping<TKey, T>> first, IEnumerable<IGrouping<TKey, T>> second, bool onlyFirstSource = false) { var intersectedKeys = first.Select(x => x.Key).Intersect(second.Select(x => x.Key)); var srcGroup = onlyFirstSource ? first : first.Union(second); return srcGroup.Where(x => intersectedKeys.Contains(x.Key)); } // グループ化したキーで差 public static IEnumerable<IGrouping<TKey, T>> GroupExcept<T, TKey>(this IEnumerable<IGrouping<TKey, T>> first, IEnumerable<IGrouping<TKey, T>> second) { var exceptedKeys = first.Select(x => x.Key).Except(second.Select(x => x.Key)); return first.Where(x => exceptedKeys.Contains(x.Key)); } }