2012-10-29 69 views
3

我目前正在研究一個C#程序,我需要結合一堆時間範圍。對於每個範圍我都有開始和結束時間。我發現一個例子,這是在Ruby中完成的,但不是在C#中完成的。我基本上是在尋找時間範圍聯盟。我覺得可能有一種方法來使用linq做到這一點,但我無法想出它。有任何想法嗎?聯合時間範圍

因此,例如

開始時間:一點30 結束時間:2:00

開始時間1:45 結束時間:14:30

開始時間:3: 00 結束時間:5:00

開始時間:4:00 結束時間:4:30

開始時間:4:45 結束時間:5:30

這組時間會回來的

開始時間:1:30 結束時間:2:30

開始時間: 3點 結束時間:5:30

+2

你可以看看這個支持TimeRanges和十字路口方法的項目:http://www.codeproject.com/Articles/168662/Time-Period-Library-for-NET –

+0

完美的,它已經像我一樣工作了通緝。謝謝! – thecaptain0220

+0

在這裏提供了一個答案:http:// stackoverflow。COM /問題/ 11480031 /合併重疊的時間間隔/ 29096584#29096584 – shannon

回答

4

這看起來很有趣,所以我開始編碼的東西。

public class TimeRanges 
{ 
    private List<TimeRange> _mergedTimeRanges = new List<TimeRange>(); 

    public void Add(TimeRange timeRange) 
    { 
     if(!_mergedTimeRanges.Any(x=>x.IsOverLap(timeRange))) 
     { 
      _mergedTimeRanges.Add(timeRange); 
      return; 
     } 
     while (_mergedTimeRanges.Any(x => x.IsOverLap(timeRange) && x!=timeRange)) 
     { 
      TimeRange toMergeRange = _mergedTimeRanges.First(x => x.IsOverLap(timeRange)); 
      toMergeRange.Merge(timeRange); 
      timeRange = toMergeRange; 
     } 
    } 

    public IEnumerable<TimeRange> GetMergedRanges() 
    { 
     return _mergedTimeRanges; 
    } 
} 
public class TimeRange 
{ 
    public DateTime Start { get; private set; } 
    public DateTime End { get; private set; } 
    public TimeRange(DateTime start, DateTime end) 
    { 
     if (start >= end) 
      throw new ArgumentException("Invalid time range, end must be later than start"); 
     Start = start; 
     End = end; 
    } 

    public void Merge(TimeRange timeRange) 
    { 
     if (!IsOverLap(timeRange)) 
      throw new ArgumentException("Cannot merge timeranges that don't overlap", "timeRange"); 
     if (End < timeRange.End) 
      End = timeRange.End; 
     if (timeRange.Start < Start) 
      Start = timeRange.Start; 
    } 

    public bool IsOverLap(TimeRange timeRange) 
    { 
     if (timeRange.End < Start) 
      return false; 
     if (timeRange.Start > End) 
      return false; 
     return true; 
    } 

    public bool Equals(TimeRange other) 
    { 
     if (ReferenceEquals(null, other)) return false; 
     if (ReferenceEquals(this, other)) return true; 
     return other.Start.Equals(Start) && other.End.Equals(End); 
    } 

    public override bool Equals(object obj) 
    { 
     if (ReferenceEquals(null, obj)) return false; 
     if (ReferenceEquals(this, obj)) return true; 
     if (obj.GetType() != typeof (TimeRange)) return false; 
     return Equals((TimeRange) obj); 
    } 

    public override int GetHashCode() 
    { 
     unchecked 
     { 
      return (Start.GetHashCode()*397)^End.GetHashCode(); 
     } 
    } 
} 

我有一對夫婦的試驗,如果有人有興趣

1

約翰·拉鬆的回答對我幫助很大。 我用它,並在下面的情況下打了一個無限的while循環,所以我想我會貢獻。

開始時間:1:30結束時間:2:00

開始時間:2:45結束時間:4:00

開始時間:1:45結束時間:3:00 (重疊的前兩個範圍)

因此,這裏是什麼,我想出了一個濃縮版:

private static IEnumerable<TimeRange> MergeTimeRanges(IEnumerable<TimeRange> ranges) 
{ 
    var mergedRanges = new List<TimeRange>(); 

    foreach (var range in ranges) 
    { 
     var overlapping = mergedRanges.Where(r => !(range.End < r.Start) && !(range.Start> r.End)).ToArray(); 
     if (overlapping.Length == 0) 
     { 
      mergedRanges.Add(range); 
     } 
     else 
     { 
      // add a new range made up of the overlapping ranges plus the new range, then delete the ovelapping ranges 
      mergedRanges.Add(new TimeRange { Start = Math.Min(range.Start, overlapping.Min(r => r.Start)), End = Math.Max(range.End, overlapping.Max(r => r.End)) }); 
      foreach (var r in overlapping) 
       mergedRanges.Remove(r); 
     } 
    } 

    return mergedRanges; 
} 

注:關於第二個想法,無限循環問題英里通過對初始範圍(?)進行排序已經避免了ght。不確定。