加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

在C#中有效地加入两个有序序列

发布时间:2020-12-15 22:44:41 所属栏目:百科 来源:网络整理
导读:设定这两个有序序列: var outer = new char[] { 'a','b','c','d','e' };var inner = new char[] { 'a','d' }; 知道两个序列中的元素是有序的,它们如何比Enumerable.Join更有效地内部连接以产生以下序列的元组? { 'a','a' }{ 'b','b' }{ 'b','b' }{ 'c','c'
设定这两个有序序列:

var outer = new char[] { 'a','b','c','d','e' };
var inner = new char[] { 'a','d' };

知道两个序列中的元素是有序的,它们如何比Enumerable.Join更有效地内部连接以产生以下序列的元组?

{ 'a','a' }
{ 'b','b' }
{ 'b','b' }
{ 'c','c' }
{ 'c','c' }
{ 'd','d' }
{ 'd','d' }

请注意,与Enumerable.Intersect不同,Enumerable.Intersect只生成两个序列中的不同元素,此处的输出序列返回元组,这些元组表示一对一,一对多或多对多关系中的每个元素组合.

语义与SQL Server中的INNER JOIN非常相似.但是,更具体地说,我正在寻找具有merge join算法(INNER MERGE JOIN)的性能特征的C#实现,该算法返回具有延迟执行的IEnumerable.

所需的方法签名可能如下所示:

IEnumerable<TResult> MergeJoin<TOuter,TInner,TKey,TResult>(
    this IEnumerable<TOuter> outer,IEnumerable<TInner> inner,Func<TOuter,TKey> outerKeySelector,Func<TInner,TKey> innerKeySelector,TResult> resultSelector)

解决方法

我不知道任何现有的Enumerable扩展方法可以实现这一点,并且没有人应该花费比我更多的时间来提出这个.

public static IEnumerable<TResult> MergeJoin<TOuter,TResult>(this IEnumerable<TOuter> outer,TResult> resultSelector)
{
    if (outer == null)
        throw new ArgumentNullException(nameof(outer));

    if (inner == null)
        throw new ArgumentNullException(nameof(inner));

    if (outerKeySelector == null)
        throw new ArgumentNullException(nameof(outerKeySelector));

    if (innerKeySelector == null)
        throw new ArgumentNullException(nameof(innerKeySelector));

    if (resultSelector == null)
        throw new ArgumentNullException(nameof(resultSelector));

    return MergeJoinIterator(outer,inner,outerKeySelector,innerKeySelector,resultSelector,Comparer<TKey>.Default);
}

public static IEnumerable<TResult> MergeJoin<TOuter,TResult> resultSelector,IComparer<TKey> comparer)
{
    if (outer == null)
        throw new ArgumentNullException(nameof(outer));

    if (inner == null)
        throw new ArgumentNullException(nameof(inner));

    if (outerKeySelector == null)
        throw new ArgumentNullException(nameof(outerKeySelector));

    if (innerKeySelector == null)
        throw new ArgumentNullException(nameof(innerKeySelector));

    if (resultSelector == null)
        throw new ArgumentNullException(nameof(resultSelector));

    if (comparer == null)
        throw new ArgumentNullException(nameof(comparer));

    return MergeJoinIterator(outer,comparer);
}

private static IEnumerable<TResult> MergeJoinIterator<TOuter,TResult>(IEnumerable<TOuter> outer,IComparer<TKey> comparer)
{
    IEnumerator<TOuter> outerEnumerator = outer.GetEnumerator();

    if (!outerEnumerator.MoveNext())
        yield break;

    IEnumerator<TInner> innerEnumerator = inner.GetEnumerator();

    if (!innerEnumerator.MoveNext())
        yield break;

    TOuter outerElement = outerEnumerator.Current;
    TKey outerKey = outerKeySelector(outerElement);

    TInner innerElement = innerEnumerator.Current;
    TKey innerKey = innerKeySelector(innerElement);

    int comp = comparer.Compare(innerKey,outerKey);

    while (true)
    {
        if (comp < 0)
        {
            if (!innerEnumerator.MoveNext())
                break;

            innerElement = innerEnumerator.Current;
            innerKey = innerKeySelector(innerElement);
            comp = comparer.Compare(innerKey,outerKey);
            continue;
        }

        if (comp > 0)
        {
            if (!outerEnumerator.MoveNext())
                break;

            outerElement = outerEnumerator.Current;
            outerKey = outerKeySelector(outerElement);
            comp = comparer.Compare(innerKey,outerKey);
            continue;
        }

        yield return resultSelector(outerElement,innerElement);

        if (!outerEnumerator.MoveNext())
        {
            while (true)
            {
                if (!innerEnumerator.MoveNext())
                    break;

                innerElement = innerEnumerator.Current;
                innerKey = innerKeySelector(innerElement);
                comp = comparer.Compare(innerKey,outerKey);

                if (comp != 0)
                    break;

                yield return resultSelector(outerElement,innerElement);
            }

            break;
        }

        if (!innerEnumerator.MoveNext())
        {
            while (true)
            {
                outerElement = outerEnumerator.Current;
                outerKey = outerKeySelector(outerElement);
                comp = comparer.Compare(innerKey,innerElement);

                if (!outerEnumerator.MoveNext())
                    break;
            }

            break;
        }

        TOuter outerElementNext = outerEnumerator.Current;
        TKey outerKeyNext = outerKeySelector(outerElementNext);

        TInner innerElementNext = innerEnumerator.Current;
        TKey innerKeyNext = innerKeySelector(innerElementNext);

        comp = comparer.Compare(outerKeyNext,outerKey);
        bool stop = false;

        if (comp != 0)
        {
            comp = comparer.Compare(innerKeyNext,innerKey);

            if (comp == 0)
            {
                yield return resultSelector(outerElement,innerElementNext);

                while (true)
                {
                    if (!innerEnumerator.MoveNext())
                    {
                        stop = true;
                        break;
                    }

                    innerElementNext = innerEnumerator.Current;
                    innerKeyNext = innerKeySelector(innerElementNext);
                    comp = comparer.Compare(innerKeyNext,outerKey);

                    if (comp != 0)
                        break;

                    yield return resultSelector(outerElement,innerElementNext);
                }

                if (stop)
                    break;
            }

            outerElement = outerElementNext;
            outerKey = outerKeyNext;
            innerElement = innerElementNext;
            innerKey = innerKeyNext;
            comp = comparer.Compare(innerKey,outerKey);
            continue;
        }

        comp = comparer.Compare(innerKeyNext,innerKey);

        if (comp != 0)
        {
            yield return resultSelector(outerElementNext,innerElement);

            while (true)
            {
                if (!outerEnumerator.MoveNext())
                {
                    stop = true;
                    break;
                }

                outerElementNext = outerEnumerator.Current;
                outerKeyNext = outerKeySelector(outerElementNext);
                comp = comparer.Compare(innerKey,outerKeyNext);

                if (comp != 0)
                    break;

                yield return resultSelector(outerElementNext,innerElement);
            }

            if (stop)
                break;

            outerElement = outerElementNext;
            outerKey = outerKeyNext;
            innerElement = innerElementNext;
            innerKey = innerKeyNext;
            comp = comparer.Compare(innerKey,innerElementNext);
        var innerRest = new List<TInner>();

        TInner innerElementFollowing = default(TInner);
        TKey innerKeyFollowing = default(TKey);

        while (true)
        {
            if (!innerEnumerator.MoveNext())
            {
                stop = true;
                break;
            }

            innerElementFollowing = innerEnumerator.Current;
            innerKeyFollowing = innerKeySelector(innerElementFollowing);
            comp = comparer.Compare(innerKeyFollowing,outerKey);

            if (comp != 0)
                break;

            yield return resultSelector(outerElement,innerElementFollowing);
            innerRest.Add(innerElementFollowing);
        }

        yield return resultSelector(outerElementNext,innerElement);
        yield return resultSelector(outerElementNext,innerElementNext);

        for (int i = 0; i < innerRest.Count; i++)
            yield return resultSelector(outerElementNext,innerRest[i]);

        while (true)
        {
            if (!outerEnumerator.MoveNext())
            {
                stop = true;
                break;
            }

            outerElementNext = outerEnumerator.Current;
            outerKeyNext = outerKeySelector(outerElementNext);
            comp = comparer.Compare(innerKey,outerKeyNext);

            if (comp != 0)
                break;

            yield return resultSelector(outerElementNext,innerElement);
            yield return resultSelector(outerElementNext,innerElementNext);

            for (int i = 0; i < innerRest.Count; i++)
                yield return resultSelector(outerElementNext,innerRest[i]);
        }

        if (stop)
            break;

        outerElement = outerElementNext;
        outerKey = outerKeyNext;
        innerElement = innerElementFollowing;
        innerKey = innerKeyFollowing;
        comp = comparer.Compare(innerKey,outerKey);
    }
}

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读