2016-07-22 20 views
1

Ich habe eine Sammlung von Objekten, die ich durch iterieren und Sachen mit tun muss. Scheint einfach bis jetzt. Ich habe jedoch einige Bedingungen, die es ziemlich kompliziert machen. Hierforeach loop mit mehreren logischen Bedingungen

einige Informationen:

Die Sammlung enthält eine Reihe von „Planet“ Objekte, die Planetenphasenzeiten haben.

Planetensichtzeiten werden zu Blöcken zusammengefasst, wenn die Zeitspanne zwischen zwei Phasen kleiner oder gleich 30 Minuten ist.

Zum Beispiel sind hier 6 Phasenzeiten:

  • Phase 1: 8.00 bis 09.30 Uhr
  • Phase 2: 10.00 bis 11.00
  • Phase 3: 11.20 bis 12.30
  • Phase 4: 14.00 bis 16.00 Uhr
  • Phase 5: 18.30 bis 19.30
  • Phase 6: 19.45 bis 09.00 Uhr

Mit den obigen Daten haben wir die folgenden Blöcke:

  • Phase 1 bis Phase 3: eine durchgehender Sichtblock
  • Phase 4: getrennter Betrachtungsblock
  • Phase 5 und Phase 6 : ein continuuous Betrachtungsblock

Math:

  • (Phase 2 Startzeit) - (Phase 1 Endzeit) = 30 Minuten
  • (Phase 3 Startzeit) - (Phase 2 Endzeit) = 20 Minuten
  • (Phase 4 Startzeit) - (Phase 3 Endzeit) = 90 Minuten
  • (Phase 5 Startzeit) - (Phase 4 Endzeit) = 150 Minuten
  • (Phase 6 Startzeit) - (Phase 5 Endzeit) = 15 Minuten

Mein fehlgeschlagener Versuch bis jetzt:

Ich habe Stunden auf dieser blöden Schleife verbracht und ich denke, dass eine andere Reihe von Augen es gut tun würde.

Es fühlt sich zu komplex, zu altmodisch und zu verwirrend an. Gibt es einen besseren/modernen Weg, dies zu tun?

Danke!

+0

Phasen Kreises Do nach Mitternacht zurück? Mit anderen Worten, machen '12:15 Uhr - 2:30 Uhr' und '22:00 Uhr - 23:50 Uhr 'eine einzige Betrachtung? – dasblinkenlight

+0

Wenn continueBlocking X, sonst X. X = X. Warum verwenden Sie continueBlocking? – Berkay

+0

Haben Sie sich eher mit Fallanweisungen als mit mehreren if -Anweisungen beschäftigt? – tCoe

Antwort

1

wie die Gruppierung könnte sehr bequem durchgeführt werden, wenn Sie mehrere Schleifen in eine zählbare-Rückkehr packen Verfahren mit yield return:

private static readonly TimeSpan HalfHour = TimeSpan.Parse("0:30"); 

private static IEnumerable<Schedule> Group(IList<GalaxySector> all) { 
    // Protect from division by zero 
    if (all.Count == 0) { 
     yield break; 
    } 
    // Find initial location 
    var pos = 0; 
    while (pos < all.Count) { 
     var prior = (pos + all.Count - 1) % all.Count; 
     if (all[prior].End+HalfHour >= all[pos].Begin) { 
      pos++; 
     } else { 
      break; 
     } 
    } 
    // Protect from wrap-around when all items belong to a single window 
    pos = pos % all.Count; 
    // Start grouping items together 
    var stop = pos; 
    do { 
     var start = pos; 
     var next = (pos+1) % all.Count; 
     while (next != stop && all[pos].End+HalfHour >= all[next].Begin) { 
      pos = next; 
      next = (pos+1) % all.Count; 
     } 
     yield return new Schedule {Begin = all[start].Begin, End = all[pos].End}; 
     pos = next; 
    } while (pos != stop); 
} 

Der obige Code "wrap around" für Mitternacht durchführt (demo).

Der Ansatz ist relativ einfach: Die erste Schleife findet den Ort, von dem aus die Iteration beginnen soll, indem sie einen Schritt zurückschaut, so dass der Plan nach dem Wrap-Around fortlaufend ist. Die zweite Schleife merkt sich die Startposition und rückt einen Schritt nach dem anderen vor und prüft, ob die Fenster näher als eine halbe Stunde voneinander entfernt sind. Sobald eine ausreichend große Pause gefunden wurde oder wenn wir den Ausgangspunkt wieder erreichen, stoppt die zweite Schleife.

Wenn Sie nicht lieber yield return verwenden möchten, können Sie es durch Hinzufügen von Elementen zu einem List<Schedule> ersetzen.

var all = new GalaxySector[] { 
    new GalaxySector {Begin=TimeSpan.Parse("0:15"), End=TimeSpan.Parse("2:30")} 
, new GalaxySector {Begin=TimeSpan.Parse("2:45"), End=TimeSpan.Parse("3:30")} 
, new GalaxySector {Begin=TimeSpan.Parse("8:00"), End=TimeSpan.Parse("9:30")} 
, new GalaxySector {Begin=TimeSpan.Parse("10:00"), End=TimeSpan.Parse("11:00")} 
, new GalaxySector {Begin=TimeSpan.Parse("11:20"), End=TimeSpan.Parse("12:30")} 
, new GalaxySector {Begin=TimeSpan.Parse("14:00"), End=TimeSpan.Parse("16:00")} 
, new GalaxySector {Begin=TimeSpan.Parse("18:30"), End=TimeSpan.Parse("19:30")} 
, new GalaxySector {Begin=TimeSpan.Parse("19:45"), End=TimeSpan.Parse("21:00")} 
, new GalaxySector {Begin=TimeSpan.Parse("22:00"), End=TimeSpan.Parse("23:50")} 
}; 
foreach (var sched in Group(all)) { 
    Console.WriteLine("{0}..{1}", sched.Begin, sched.End); 
} 

Ausgang:

08:00:00..12:30:00 
14:00:00..16:00:00 
18:30:00..21:00:00 
22:00:00..03:30:00 
+0

Ich habe Ihre Antwort akzeptiert, aber mit dem obigen Code können die Symbole "Begin" oder "End" nicht aufgelöst werden. – SkyeBoniwell

1

Unter der Annahme, dass diese Termine sind und nicht nur Tageszeiten können Sie folgendes tun

var galaxySector = new List<PlanetPhase> 
{ 
    new PlanetPhase 
    { 
     Name = "Saturn", 
     StartDatePhase = new DateTime(2016, 7, 22, 8, 0, 0), 
     EndDatePhase = new DateTime(2016, 7, 22, 9, 30, 0) 
    }, 
    new PlanetPhase 
    { 
     Name = "Saturn", 
     StartDatePhase = new DateTime(2016, 7, 22, 10, 0, 0), 
     EndDatePhase = new DateTime(2016, 7, 22, 11, 0, 0) 
    }, 
    new PlanetPhase 
    { 
     Name = "Saturn", 
     StartDatePhase = new DateTime(2016, 7, 22, 11, 20, 0), 
     EndDatePhase = new DateTime(2016, 7, 22, 12, 30, 0) 
    }, 
    new PlanetPhase 
    { 
     Name = "Saturn", 
     StartDatePhase = new DateTime(2016, 7, 22, 14, 0, 0), 
     EndDatePhase = new DateTime(2016, 7, 22, 16, 0, 0) 
    }, 
    new PlanetPhase 
    { 
     Name = "Saturn", 
     StartDatePhase = new DateTime(2016, 7, 22, 18, 30, 0), 
     EndDatePhase = new DateTime(2016, 7, 22, 19, 30, 0) 
    }, 
    new PlanetPhase 
    { 
     Name = "Saturn", 
     StartDatePhase = new DateTime(2016, 7, 22, 19, 45, 0), 
     EndDatePhase = new DateTime(2016, 7, 22, 21, 0, 0) 
    }, 
}; 


PlanetPhase previous = null; 
int groupon = 0; 
var results = galaxySector.GroupBy(p => p.Name) 
    .Select(grp => new 
    { 
     PlanetName = grp.Key, 
     Phases = grp.OrderBy(p => p.StartDatePhase) 
      .Select(p => 
      { 
       if (previous != null 
        && p.StartDatePhase - previous.EndDatePhase > TimeSpan.FromMinutes(30)) 
       { 
        groupon++; 
       } 

       previous = p; 

       return new 
       { 
        groupOn = groupon, 
        p.StartDatePhase, 
        p.EndDatePhase 
       }; 
      }) 
      .GroupBy(x => x.groupOn) 
      .Select(g => new 
      { 
       Start = g.Min(x => x.StartDatePhase), 
       End = g.Max(x => x.EndDatePhase) 
      }) 
      .ToList() 
    }); 

foreach (var r in results) 
{ 
    Console.WriteLine(r.PlanetName); 
    foreach (var p in r.Phases) 
     Console.WriteLine($"\t{p.Start} - {p.End}"); 
} 

Das wird ausgegeben

Saturn

7/22/2016 8:00: 00 AM - 7/22/2016 12:30:00 PM

7/22/2016 2:00:00 PM - 7/22/2016 4:00:00 PM

7/22/2016 6:30:00 PM - 2016.07.22 21.00.00