IEnumerable扩展左连接 方法

using System;
using System.Collections.Generic;
using System.Linq;

namespace Project.Lib {
    /// <summary>
    /// IEnumerable扩展左连接的三种方法
    /// </summary>
    public static class IEnumerableExtensions {
        public static IEnumerable<TResult> LeftOuterJoin<TLeft, TRight, TKey, TResult>(this IEnumerable<TLeft> left, IEnumerable<TRight> right, Func<TLeft, TKey> leftKey, Func<TRight, TKey> rightKey,
            Func<TLeft, TRight, TResult> result) {
            return left.GroupJoin(right, leftKey, rightKey, (l, r) => new { l, r })
                .SelectMany(
                    o => o.r.DefaultIfEmpty(),
                    (l, r) => new { lft = l.l, rght = r })
                .Select(o => result.Invoke(o.lft, o.rght));
        }
        public static IEnumerable<TResult> LeftJoin<TOuter, TInner, TKey, TResult>(this IEnumerable<TOuter> outer,
            IEnumerable<TInner> inner, Func<TOuter, TKey> outerKeySelector, Func<TInner, TKey> innerKeySelector,
            Func<TOuter, TInner, TResult> resultSelector) {
            return outer
                .GroupJoin(inner, outerKeySelector, innerKeySelector, (outerObj, inners) =>
                    new {
                        outerObj,
                        inners = inners.DefaultIfEmpty()
                    })
                .SelectMany(a => a.inners.Select(innerObj => resultSelector(a.outerObj, innerObj)));
        }
        public static IEnumerable<Result> LeftJoin<TOuter, TInner, TKey, Result>(
            this IEnumerable<TOuter> outer
            , IEnumerable<TInner> inner
            , Func<TOuter, TKey> outerKeySelector
            , Func<TInner, TKey> innerKeySelector
            , Func<TOuter, TInner, Result> resultSelector
            , IEqualityComparer<TKey> comparer) {
            if (outer == null)
                throw new ArgumentException("outer");

            if (inner == null)
                throw new ArgumentException("inner");

            if (outerKeySelector == null)
                throw new ArgumentException("outerKeySelector");

            if (innerKeySelector == null)
                throw new ArgumentException("innerKeySelector");

            if (resultSelector == null)
                throw new ArgumentException("resultSelector");

            return LeftJoinImpl(outer, inner, outerKeySelector, innerKeySelector, resultSelector, comparer ?? EqualityComparer<TKey>.Default);
        }

        static IEnumerable<Result> LeftJoinImpl<TOuter, TInner, TKey, Result>(
            IEnumerable<TOuter> outer, IEnumerable<TInner> inner
            , Func<TOuter, TKey> outerKeySelector
            , Func<TInner, TKey> innerKeySelector
            , Func<TOuter, TInner, Result> resultSelector
            , IEqualityComparer<TKey> comparer) {
            var innerLookup = inner.ToLookup(innerKeySelector, comparer);

            foreach (var outerElment in outer) {
                var outerKey = outerKeySelector(outerElment);
                var innerElements = innerLookup[outerKey];

                if (innerElements.Any())
                    foreach (var innerElement in innerElements)
                        yield return resultSelector(outerElment, innerElement);
                else
                    yield return resultSelector(outerElment, default(TInner));
            }
        }
    }
}

 

posted @ 2020-03-26 14:36  liliyou  阅读(343)  评论(0编辑  收藏  举报