2015-12-01 33 views
10

Biorąc pod uwagę zakresy dat, chciałbym uzyskać listę sąsiadujących zakresów dat.Uzyskiwanie ciągłych zakresów dat

enter image description here

nie jestem zbyt pewny terminologii co szukam, ale już ułożyła szkielet:

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

Czy istnieje sposób, aby wyprowadzić przyległe zakresy?

+0

więc to, co jest twoje pytanie .. co za problem i czy problem z istniejącym kodem ..? co się stanie, gdy uruchomisz kod ...? – MethodMan

+0

Hi MethodMan, nie znam algorytmu do wdrożenia w GetContiguousTimespans(). Podjęta przeze mnie próba jest chaotyczna i nie chcę zanieczyszczać szkieletu – Fidel

+0

czy to działa ...? – MethodMan

Odpowiedz

7

Nie jestem pewien czy to zrozumieć całkowicie, ale dotyczące tego, co jest napisane, a dane testowe to powinno działać:

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

Oczywiście to też trzeba będzie dodać kilka czeków do wartości granicznych, ale ogólna idea powinna być jasne, myślę.

+0

uwaga: nie musisz sprawdzać 'zakresów [i] .Start> = cur.Start', ponieważ już wcześniej sortowałeś zakresy przed rozpoczęciem. –

+0

Masz rację - ta część wyrażenia jest zawsze prawdziwa) Pozostaje tam z poprzedniej wersji. Ale z drugiej strony jest nieco łatwiej zrozumieć, co się dzieje z tym stanem) W każdym razie, dzięki! – MagisterCrazy

+0

To całkiem niezły Magister, dziękuję za algorytm! – Fidel

1

Dziękuję Kiwi. Spojrzałem na Time Period Library i ma funkcję o nazwie "Time Period Combiner", który jest dokładnie tym, czego szukałem.

enter image description here

I kod używać go w moim przypadku było:

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

Więc jeśli zacznę z tego wejścia:

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")), 
}; 

Wtedy to działa dla mnie:

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

Wynik końcowy otrzymuję to:

results