2009-08-06 15 views
3

Als Folge der Methode collapses overlapping ranges dachte ich, ich würde versuchen, eine Methode zu erstellen, die benachbarte Bereiche kombiniert.C#: Kombinieren benachbarter Bereiche

Grundsätzlich nach dem Zusammenbruch Verfahren laufen Sie mit zum Beispiel am Ende kann 1 bis 5 und 6 bis 10 würde Ich mag diese in einem Bereich kombinieren, 1 bis 10.

Dies ist, was ich gekommen bin, bis jetzt, aber es funktioniert nicht wirklich gut. Hat jemand mein Problem entdeckt oder eine gute Alternativlösung?

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, haben Sie überprüft, meine Lösung? War das nicht was du wolltest? –

+0

Habe noch keine der Antworten getestet. Will tun, wenn ich am Montag wieder zur Arbeit komme =) – Svish

Antwort

0

Ich habe diese Lösung erreicht. Voraussetzung ist, dass die Bereiche je nach Func aufsteigend/absteigend geordnet sind. Es wird benachbarte Bereiche zusammenführen und es ist noch eine verzögerte Ausführung. Ich habe nicht viele Tests durchgeführt, also könnte es Grenzfälle geben, die das brechen. Sei gentile :-)

Edit: Verkürzte den Code ein bisschen. Soweit ich sehen kann, funktioniert es. Ausgelassen null überprüft, obwohl.

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

ist das letzte 'sonst Ausbeute Pause;' wirklich notwendig? – Svish

+0

endete mit dieser, aber verkürzte es leicht. – Svish

1

Es werden nur zwei benachbarte Bereiche zusammengeführt, nicht drei oder mehr. Behalten Sie die letzte, bis Sie eine Lücke oder das Ende der Liste finden.

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