设定这两个有序序列:
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); } }
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。