2009-08-06 5 views
3

collapses overlapping ranges 인접한 범위를 결합하는 방법을 만들려고 시도하는 방법에 대한 후속 조치로.C# : 인접 범위 결합하기

기본적으로 축소 방법을 실행 한 후 5 예 1 끝낼 수 있으며, 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, 당신은 내 솔루션을 확인했다? 이게 니가 원하는거야? –

+0

아직 답변을 테스트하지 못했습니다. 내가 월요일에 일하러 돌아올 때 =) – Svish

답변

0

이 솔루션에 도달했습니다. 하나의 전제 조건은 범위가 Func에 따라 오름차순/내림차순으로 정렬된다는 것입니다. 그것은 인접한 범위를 병합 할 것이고 여전히 실행 지연이 있습니다. 나는 많은 테스트를 수행하지 않았으므로 이것을 극복하는 최악의 경우가있을 수 있습니다. 이방 사람이 되십시오 :-)

편집 : 코드를 조금 줄였습니다. 내가 볼 수있는 한 멀리 작동합니다. 그래도 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

는 마지막 '그 밖의 yield break;가 정말로 필요합니까? – Svish

+0

이 하나를 사용하여 끝났지 만 약간 줄였습니다. – Svish

1

3 개가 아닌 2 개의 인접 범위 만 병합합니다. 갭이나리스트의 끝을 찾을 때까지 마지막 것을 유지하십시오.

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