IEnumerable的一些基本方法 补充

接上一篇,我们发现两表连接方式默认为内连接,而我们在SQL中常用到的左连接没有封装方法。换句话说,微软放弃两表左连或右连的这种做法(只有在2个表都存在值时,这样的连接才有意义)。

如果要实现表的左连接,就不能调用他现有的封装方法了,可以用LINQ来实现。

var joinTable = (from left in table1.AsEnumerable()
                    join right in table2.AsEnumerable()
                    on left["ID"].ToString() equals right["ID"].ToString() into newTable
                    from right in newTable.DefaultIfEmpty()
                    select new
                    {
                        LeftID = left["ID"].ToString(),
                        RightID = right != null ? right["ID"].ToString() : default(string),
                        LeftName = left["Name"].ToString(),
                        RightName = right != null ? right["Name"].ToString() : default(string)
                    }).ToList();
joinTable.ForEach(t => Console.WriteLine("{0}\t{1}\t{2}\t{3}", t.LeftID, t.RightID, t.LeftName, t.RightName));

功能是实现了,但是这样又要憋死一群强迫症患者,非要用Join封装方法来实现这个功能。

那我们就来手动封装一个左连接方法吧。

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));
    }
}

PS:以上这段代码转载自stackoverflow.com

var joinTable = table1.AsEnumerable().LeftJoin(table2.AsEnumerable(),
    left => left["ID"].ToString(),
    right => right["ID"].ToString(),
    (left, right) => new
    {
        LeftID = left["ID"].ToString(),
        RightID = right != null ? right["ID"].ToString() : default(string),
        LeftName = left["Name"].ToString(),
        RightName = right != null ? right["Name"].ToString() : default(string)
    }, null).ToList();
joinTable.ForEach(t => Console.WriteLine("{0}\t{1}\t{2}\t{3}", t.LeftID, t.RightID, t.LeftName, t.RightName));

是不是和之前的Join方法一样,这样用起来很方便了吧。

posted @ 2017-05-31 14:58  TanSea  阅读(582)  评论(0编辑  收藏  举报