2009-08-06 3 views
3

collapses overlapping rangesの方法のフォローアップとして、隣接する範囲を結合する方法を作成しようと考えました。C#:隣接する範囲を結合する

基本的に、あなたは10に5と6に例えば1で終わる可能性が折りたたみメソッドを実行した後、私は1つの範囲にそれらを結合したいと思い、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

私はこの解決策に達しました。 1つの前提条件は、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

は最後の 'else 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; 
} 
関連する問題