2015-12-01 8 views
10

Angesichts einer Liste von Datumsbereichen möchte ich eine Liste zusammenhängender Zeiträume erhalten.Abrufen zusammenhängender Zeiträume

enter image description here

Ich bin nicht sicher, die Terminologie von dem, was ich suche, aber ich habe zusammen ein Skelett setzen:

using System; 
using System.Collections.Generic; 
using System.Diagnostics; 
using System.Linq; 
using System.Text; 

namespace ContiguousTimeSpans 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      List<DateRange> ranges = new List<DateRange>(); 
      ranges.Add(new DateRange(DateTime.Parse("01/12/2015 07:00:00"), DateTime.Parse("01/12/2015 10:00:00"))); 
      ranges.Add(new DateRange(DateTime.Parse("01/12/2015 06:00:00"), DateTime.Parse("01/12/2015 09:00:00"))); 
      ranges.Add(new DateRange(DateTime.Parse("01/12/2015 05:00:00"), DateTime.Parse("01/12/2015 08:00:00"))); 
      ranges.Add(new DateRange(DateTime.Parse("01/12/2015 18:00:00"), DateTime.Parse("01/12/2015 21:00:00"))); 
      ranges.Add(new DateRange(DateTime.Parse("01/12/2015 12:00:00"), DateTime.Parse("01/12/2015 14:00:00"))); 
      ranges.Add(new DateRange(DateTime.Parse("01/12/2015 20:00:00"), DateTime.Parse("01/12/2015 22:00:00"))); 
      ranges.Add(new DateRange(DateTime.Parse("01/12/2015 11:00:00"), DateTime.Parse("01/12/2015 23:00:00"))); 

      List<DateRange> contiguousBlocks = GetContiguousTimespans(ranges); 
      Debug.Assert(contiguousBlocks.Count == 2); 

      Debug.Assert(contiguousBlocks[0].Start.Hour == 5); 
      Debug.Assert(contiguousBlocks[0].End.Hour == 10); 

      Debug.Assert(contiguousBlocks[1].Start.Hour == 11); 
      Debug.Assert(contiguousBlocks[1].End.Hour == 23); 

      Console.ReadKey(); 
     } 

     public static List<DateRange> GetContiguousTimespans(List<DateRange> ranges) 
     { 
      List<DateRange> result = new List<DateRange>(); 
      //??? 
      return result; 
     } 
    } 

    public class DateRange 
    { 
     public DateTime Start { get; set; } 
     public DateTime End { get; set; } 

     public DateRange(DateTime start, DateTime end) 
     { 
      Start = start; 
      End = end; 
     } 
    } 
} 

Gibt es eine Möglichkeit, die zusammenhängenden abzuleiten Bereiche?

+0

so, was Ihre Frage .. was ist das Problem und oder Problem mit Ihrem vorhandenen Code ..? Was passiert, wenn Sie den Code ausführen ..? – MethodMan

+0

Hi MethodMan, ich kenne den Algorithmus nicht, der in GetContiguousTimespans() implementiert werden soll. Der Versuch, den ich gemacht habe, ist unordentlich und ich möchte das Skelett nicht verschmutzen – Fidel

+0

funktioniert es ..? – MethodMan

Antwort

7

nicht sicher, ob ich verstehe das vollkommen, aber in Bezug auf, was geschrieben wird und die Testdaten sollten diese Arbeit:

public static List<DateRange> GetContiguousTimespans(List<DateRange> ranges) 
{ 
    List<DateRange> result = new List<DateRange>(); 
    ranges.Sort((a,b)=>a.Start.CompareTo(b.Start)); 
    DateRange cur = ranges[0]; 

    for (int i = 1; i < ranges.Count; i++) 
    { 
     if (ranges[i].Start <= cur.End) 
     { 
      if (ranges[i].End >= cur.End) 
       cur.End = ranges[i].End; 
     } 
     else 
     { 
      result.Add(cur); 
      cur = ranges[i]; 
     } 
    } 

    result.Add(cur); 

    return result; 
} 

Natürlich sind diese müssen auch einige Prüfungen für die Grenz Werte hinzufügen, aber allgemeine Idee sollte sein klar, denke ich.

+0

Hinweis: Sie müssen nicht 'ranges [i] .Start> = cur.Start' überprüfen, da Sie die Bereiche bereits vorher sortiert haben. –

+0

Sie haben Recht - dieser Teil des Ausdrucks ist immer wahr) Es bleibt dort von einer früheren Version. Aber auf der anderen Seite ist es ein bisschen einfacher zu verstehen, was mit dieser Bedingung passiert) Wie auch immer, danke! – MagisterCrazy

+0

Das ist ganz schön Magister, danke für den Algorithmus! – Fidel

1

Vielen Dank Kiwi. Ich habe mir die Time Period Library angesehen und es hat eine Funktion namens "Time Period Combiner", die genau das ist, wonach ich gesucht habe.

enter image description here

Und der Code es in meinem Fall zu verwenden, war:

public static List<DateRange> GetContiguousTimespans(List<DateRange> ranges) 
{ 
    //convert my DateRange objects into the objects used by the Time Period Library 
    TimePeriodCollection periods = new TimePeriodCollection(); 
    ranges.ForEach(ts => periods.Add(new TimeRange(ts.Start, ts.End))); 

    //get a list of contiguous date ranges 
    TimePeriodCombiner<TimeRange> periodCombiner = new TimePeriodCombiner<TimeRange>(); 
    ITimePeriodCollection combinedPeriods = periodCombiner.CombinePeriods(periods); 

    //convert the objects back to DateRanges 
    List<DateRange> result = combinedPeriods.Select(cp => new DateRange(cp.Start, cp.End)).ToList(); 
    return result; 
} 
2

Also, wenn ich mit diesem Eingang zu starten:

List<DateRange> ranges = new List<DateRange>() 
{ 
    new DateRange(DateTime.Parse("01/12/2015 07:00:00"), DateTime.Parse("01/12/2015 10:00:00")), 
    new DateRange(DateTime.Parse("01/12/2015 06:00:00"), DateTime.Parse("01/12/2015 09:00:00")), 
    new DateRange(DateTime.Parse("01/12/2015 05:00:00"), DateTime.Parse("01/12/2015 08:00:00")), 
    new DateRange(DateTime.Parse("01/12/2015 18:00:00"), DateTime.Parse("01/12/2015 21:00:00")), 
    new DateRange(DateTime.Parse("01/12/2015 12:00:00"), DateTime.Parse("01/12/2015 14:00:00")), 
    new DateRange(DateTime.Parse("01/12/2015 20:00:00"), DateTime.Parse("01/12/2015 22:00:00")), 
    new DateRange(DateTime.Parse("01/12/2015 11:00:00"), DateTime.Parse("01/12/2015 23:00:00")), 
}; 

Dann ist dieses für mich funktioniert:

var ordered = ranges.OrderBy(x => x.Start).ThenBy(x => x.End).ToArray(); 

var working = 
    ordered 
     .Skip(1) 
     .Aggregate(new 
     { 
      contiguous = new List<DateRange>(), 
      current = ordered.First(), 
     }, (a, r) => 
     { 
      if (a.current.End >= r.Start) 
      { 
       return new 
       { 
        a.contiguous, 
        current = r.End > a.current.End 
         ? new DateRange(a.current.Start, r.End) 
         : a.current, 
       }; 
      } 
      else 
      { 
       a.contiguous.Add(a.current); 
       return new 
       { 
        a.contiguous, 
        current = r, 
       }; 
      } 
     }); 

var results = working.contiguous; 
results.Add(working.current); 

Das Endergebnis ich erhalte, ist dies:

results

Verwandte Themen