2015-12-01 41 views
10

Được cung cấp danh sách phạm vi ngày, tôi muốn nhận danh sách các phạm vi ngày liền nhau.Nhận phạm vi ngày liền kề

enter image description here

Tôi không quá chắc chắn về các thuật ngữ của những gì tôi đang tìm kiếm, nhưng tôi đã đặt cùng một bộ xương:

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

Có cách nào để suy ra tiếp giáp các dãy?

+0

vì vậy câu hỏi của bạn là gì .. vấn đề và vấn đề với mã hiện tại của bạn là gì ..? điều gì sẽ xảy ra khi bạn chạy mã ..? – MethodMan

+0

Xin chào MethodMan, tôi không biết thuật toán để triển khai trong GetContiguousTimespans(). Nỗ lực tôi đã làm là lộn xộn và tôi không muốn làm ô nhiễm bộ xương – Fidel

+0

nó hoạt động được không ...? – MethodMan

Trả lời

7

Không chắc tôi hiểu điều này hoàn toàn, nhưng liên quan đến những gì được viết và các dữ liệu thử nghiệm này nên làm việc:

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

Tất nhiên điều này cũng sẽ cần phải thêm một số kiểm tra cho các giá trị biên giới, nhưng ý tưởng chung nên rõ ràng tôi đoán.

+0

lưu ý: bạn không cần phải kiểm tra 'phạm vi [i] .Bắt đầu> = cur.Start' bởi vì bạn đã sắp xếp phạm vi bằng cách bắt đầu trước. –

+0

Bạn nói đúng - phần này của biểu thức luôn đúng) Nó vẫn ở đó từ phiên bản trước. Nhưng mặt khác, nó dễ dàng hơn một chút để hiểu những gì đang xảy ra với tình trạng này) Dù sao, cảm ơn! – MagisterCrazy

+0

Đó là Magister khá tốt đẹp, cảm ơn bạn cho thuật toán! – Fidel

1

Cảm ơn bạn Kiwi. Tôi đã xem Time Period Library và nó có một tính năng gọi là 'Thời gian Combiner' đó là chính xác những gì tôi đang tìm kiếm.

enter image description here

Và mã để sử dụng nó trong trường hợp của tôi là:

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

Vì vậy, nếu tôi bắt đầu với đầu vào này:

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

Sau đó, các công trình này cho tôi:

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

Kết quả cuối cùng tôi nhận được là:

results

Các vấn đề liên quan