2009-08-06 58 views
3

作爲collapses overlapping ranges的方法的後續,我想我會嘗試創建一種方法來組合相鄰範圍。C#:組合相鄰的範圍

基本上,運行Collapse方法後可能會結了例如1至5和6至10。我想這些組合成一個範圍,爲1〜10

這就是我來到目前爲止,但它並不能很好地發揮作用。有沒有人發現我的問題或有很好的替代解決方案?

public static IEnumerable<Range<T>> MergeAdjacent<T>(this IEnumerable<Range<T>> source, Func<T, T, bool> isAdjacent) 
    { 
     using (var sourceIterator = source.GetEnumerator()) 
     { 
      if (!sourceIterator.MoveNext()) 
       yield break; 

      var first = sourceIterator.Current; 

      while (sourceIterator.MoveNext()) 
      { 
       var second = sourceIterator.Current; 

       if (isAdjacent(first.End, second.Start)) 
       { 
        yield return Range.Create(first.Start, second.End); 
       } 
       else 
        yield return first; 

       first = second; 
      } 

      yield return first; 
     } 
    } 
+0

@Svish,你檢查我的解決方案?這不是你想要的嗎? – 2009-08-07 14:18:35

+0

還沒有得到測試任何答案。當我回到星期一上班的時候會這樣做=) – Svish 2009-08-08 19:04:53

回答

0

我已經達到了這個解決方案。一個先決條件是範圍按照Func升序/降序排列。它會合並相鄰的範圍,並且仍然延遲執行。我沒有進行大量的測試,因此可能會有邊緣案例破壞這一點。 Be gentile :-)

編輯:縮短了一下代碼。據我可以看到它的作品。儘管如此,仍然排除null

public static IEnumerable<Range<T>> MergeAdjacent<T>(this IEnumerable<Range<T>> source, Func<T, T, bool> isAdjacent) 
    { 
     using (var it = source.GetEnumerator()) 
     { 
      if (!it.MoveNext()) 
       yield break; 

      var item = it.Current; 

      while (it.MoveNext()) 
       if (isAdjacent(item.End, it.Current.Start)) 
       { 
        item = Range.Create(item.Start, it.Current.End); 
       } 
       else 
       { 
        yield return item; 
        item = it.Current; 
       } 

      yield return item; 
     } 
    } 

static void Main(string[] args) 
    { 
     var ranges = new List<Range<int>> 
     { 
      Range.Create(1,3), Range.Create(4,5), Range.Create(7,10), 
      Range.Create(11,17), Range.Create(20,32), Range.Create(33,80), 
      Range.Create(90,100), 
     }; 

     foreach (var range in ranges.MergeAdjacent((r1, r2) => r1 + 1 == r2)) 
      Console.WriteLine(range); 
    } 

    // Result: 1-5, 7-20, 25-80, 90-100 
+0

是最後一個'else yield break','真的有必要嗎? – Svish 2009-08-10 07:32:38

+0

結束了使用這一個,但稍微縮短了它。 – Svish 2009-08-10 08:04:04

1

它只會合併兩個相鄰的範圍,而不是三個或更多。保留最後一個,直到找到空位或列表的末尾。

public static IEnumerable<Range<T>> MergeAdjacent<T>(this IEnumerable<Range<T>> source, Func<T, T, bool> isAdjacent) 
{ 
    Range<T> current = null; 

    foreach (Range<T> item in source) 
    { 
     if (current == null) 
     { 
      current = item; 
     } 
     else 
     { 
      if (isAdjacent(current.End, item.Start)) 
      { 
       current = Range.Create(current.Start, item.End); 
      } 
      else 
      { 
       yield return current; 
       current = item; 
      } 
     } 
    } 

    if (current != null) 
     yield return current; 
}