2011-03-21 55 views
2

我试图找到一个优雅的方式来写一个可能被称为MergeWithRatio或ZipWithRatio的扩展方法。帮助实现一个ZipWithRatio扩展方法

我希望它有这个签名..

public static IEnumerable<T> MergeWithRatio<T>(this IEnumerable<T> source, IEnumerable<T> mergeSequence, int ratio) 
{ 
    .. 
} 

实例第一。

var source = new[]{1,2,3,4,5,6,7,8,9}; 
var mergeSeq = new[]{100,200}; 
var result = source.MergeWithRatio(mergeSeq, 3).ToArray(); 

结果现在包含[1,2,100,3,4,200,5,6,100中,7,8,200 9]

总结: 的MERGESEQ环绕时/如果完成,并且当“源”为空时,收益停止。

如果可能的话,我会优先考虑解决方案是懒惰的,但它不是一个要求。

任何想法或指针?

+0

您尚未指定结果是否可以以“mergeSequence”中的项目结尾。 – 2011-03-21 15:42:11

回答

2

这会工作,并返回预期的输出:

+1

'source'的迭代器将被'foreach'正确处理,如果可能的话,不要忘记也要处理mergeEnumerator。 – 2011-03-21 15:39:52

+0

@Ben:是的,只是修复了 – BrokenGlass 2011-03-21 15:40:33

0
public static IEnumerable<T> MergeWithRatio<T>(this IEnumerable<T> source, IEnumerable<T> mergeSequence, int ratio) 
{ 
    using (IEnumerator<T> sourceEnumerator = source.GetEnumerator(), 
          mergeSequenceEnumerator = mergeSequence.GetEnumerator()) 
    { 
     int i = 1; 
     while (sourceEnumerator.MoveNext()) 
     { 
      yield return sourceEnumerator.Current; 
      i++; 
      if (i == ratio) 
      { 
       if (!mergeSequenceEnumerator.MoveNext()) 
       { 
        mergeSequenceEnumerator.Reset(); 
        mergeSequenceEnumerator.MoveNext(); 
       } 
       yield return mergeSequenceEnumerator.Current; 
       i = 1; 
      } 
     } 
    } 
} 

加上mergeSequenceEnumerator.MoveNext()一些检查,ratio输入value`等

+1

如果可能的话,不要忘记处理两个迭代器。 – 2011-03-21 15:38:55

1

这是我实现:

public static IEnumerable<T> MergeWithRatio<T>(this IEnumerable<T> source, IEnumerable<T> mergeSequence, int ratio) 
{ 
    if (source == null) 
    { 
     throw new ArgumentNullException("source"); 
    } 

    if (mergeSequence == null) 
    { 
     throw new ArgumentNullException("mergeSequence"); 
    } 

    if (ratio <= 1) 
    { 
     throw new ArgumentOutOfRangeException("ratio must be greater one."); 
    } 

    return MergeWithRatioImpl(source, mergeSequence, ratio); 
} 

private static IEnumerable<T> MergeWithRatioImpl<T>(this IEnumerable<T> source, IEnumerable<T> mergeSequence, int ratio) 
{ 
    bool mergeSequenceContainsElements = true; 
    int i = 1; 
    ratio--; 

    using (var sourceEnumerator = source.GetEnumerator()) 
    using (var mergeSequenceEnumerator = mergeSequence.GetEnumerator()) 
    { 
     while (sourceEnumerator.MoveNext()) 
     { 
      yield return sourceEnumerator.Current; 

      if (i++ % ratio == 0) 
      { 
       if (!mergeSequenceEnumerator.MoveNext()) 
       { 
        // ToDo: Should we cache the current values for the case the 
        //  enumerator can't be reset? 
        mergeSequenceEnumerator.Reset(); 
        mergeSequenceContainsElements = mergeSequenceEnumerator.MoveNext(); 
       } 

       if (mergeSequenceContainsElements) 
       { 
        yield return mergeSequenceEnumerator.Current; 
       } 
      } 
     } 
    } 
} 
+0

+1,用于错误检查并将延期执行分离为单独的方法。 – juharr 2011-03-21 16:12:48

+0

@juharr:是的,感谢Jon并且是[EduLinq系列](http://msmvps.com/blogs/jon_skeet/archive/2011/02/23/reimplementing-linq-to-objects-part-45-conclusion-和列表的-posts.aspx)。 – Oliver 2011-03-22 08:28:33