2015-03-16 6 views
2

У меня есть список DateTimes, и мне нужно «инвертировать» (из-за отсутствия лучшего слова) этого списка.C# 'инвертировать' список DateTime

public class Available 
{ 
    public Available(DateTime startDate, DateTime endDate) 
    { 
     if (!startDate.Day.Equals(endDate.Day)) 
      throw new Exception("The start and end days are not equal."); 

     this.StartDate = startDate; 
     this.EndDate = endDate; 
    } 

    public DateTime StartDate { get; set; } 
    public DateTime EndDate { get; set; } 
} 

List<Available> availableTimes = new List<Available>() 
{ 
    new Available(new DateTime(2015, 3, 16, 08, 00, 00), new DateTime(2015, 3, 16, 10, 00, 00)), 
    new Available(new DateTime(2015, 3, 16, 12, 00, 00), new DateTime(2015, 3, 16, 14, 00, 00)), 
    new Available(new DateTime(2015, 3, 16, 15, 00, 00), new DateTime(2015, 3, 16, 16, 00, 00)), 
}; 

Мне нужно преобразовать этот список доступных раз в список блокируемых раз за этот день, но я вроде застрял. В этом случае мне необходимо:

2015-3-16 00:00 - 2015-3-16 08:00, 
2015-3-16 10:00 - 2015-3-16 12:00, 
2015-3-16 14:00 - 2015-3-16 15:00, 
2015-3-16 16:00 - 2015-3-16 23:59 

Любые яркие идеи?

+2

Проблема, о которой вы говорите, называется «пробелы и острова». Я поставил этот тег на ваш вопрос, чтобы уточнить. – DrCopyPaste

+0

Когда время, которое должно быть представлено на выходе, должно начинаться и заканчиваться? – Codor

+0

Я никогда не слышал об этом термине. Благодарю. –

ответ

5

Попробуйте это, переименовал свой класс DateTimeRange, как это имеет двойное значение в настоящее время в том числе блокированных, а также должен был сделать предположение о том, что 23:59 был полночь -1 тик.

using System; 
using System.Collections.Generic; 
using System.Linq; 

public class DateTimeRange 
{ 
    public DateTimeRange(DateTime startDate, DateTime endDate) 
    { 
     if (!startDate.Day.Equals(endDate.Day)) 
      throw new Exception("The start and end days are not equal."); 

     this.StartDate = startDate; 
     this.EndDate = endDate; 
    } 

    public DateTime StartDate { get; set; } 
    public DateTime EndDate { get; set; } 
}  



public class Program 
{ 
    static List<DateTimeRange> availableTimes = new List<DateTimeRange>() 
    { 
     new DateTimeRange(new DateTime(2015, 3, 16, 08, 00, 00), new DateTime(2015, 3, 16, 10, 00, 00)), 
     new DateTimeRange(new DateTime(2015, 3, 16, 12, 00, 00), new DateTime(2015, 3, 16, 14, 00, 00)), 
     new DateTimeRange(new DateTime(2015, 3, 16, 15, 00, 00), new DateTime(2015, 3, 16, 16, 00, 00)), 
    }; 

    private static IEnumerable<DateTimeRange> GetBlockedTimes(IEnumerable<DateTimeRange> ranges) 
    { 
     var min = ranges.Select(r => r.StartDate).Min().Date; 
     var max = ranges.Select(r => r.EndDate).Max().AddDays(1).Date.AddTicks(-1); 

     foreach(var range in ranges.OrderBy(r => r.StartDate)) 
     { 
      yield return new DateTimeRange(min, range.StartDate); 
      min = range.EndDate; 
     } 

     yield return new DateTimeRange(min, max); 
    } 

    public static void Main() 
    { 
     foreach(var item in GetBlockedTimes(availableTimes)) 
     { 
      Console.WriteLine(item.StartDate + " - " + item.EndDate); 
     } 
    } 
} 
2

Если ваш список всегда «отсортирован» и не имеет перекрытий, алгоритм не должен быть слишком сложным. «Глобальное время начала/окончания» относится к значениям 2015-3-16 00:00 и 2015-3-16 23:59 вашего примера.

start = global start time 
for each item in list: 
    yield new (start, item.start) 
    start = item.end 
yield new (start, global end time) 

Перевод его в метод C# оставлен как упражнение.

+0

Плюс вам просто не нужно считать, что список отсортирован, вы можете просто убедиться, что это до применения алгоритма;) – DrCopyPaste

+0

Что делать, если первый пункт 0:00 - 1:00? – Eric

+0

@ Эрик: Затем вы получите запись '00: 00'-'00: 00'. Проще всего просто удалить все записи «нулевой длины» после этого. (Это также применяется, если у вас есть время «1: 00-2: 00» и «2: 00-3: 00'.) – Heinzi

-2

Если вы просто хотите заказать элементы списка по дате, с ссылкой, это очень просто:

availableTimes = availableTimes.OrderByDescending(x => x.startDate).ToList(); 
0

алгоритм Heinzi превратился в C#. Предполагает, что доступные интервалы не пересекаются и сортируются.

 DateTime firstDay = availableTimes[0].StartDate; 
     DateTime previousTime = new DateTime(firstDay.Year, firstDay.Month, firstDay.Day, 0, 0, 0); 
     List<Available> unavailableTimes = new List<Available>(); 

     foreach (Available available in availableTimes) 
     { 
      unavailableTimes.Add(new Available(previousTime, available.StartDate)); 
      previousTime = available.EndDate; 
     } 

     var dateTime = previousTime.Date; 
     DateTime endDay = new DateTime(dateTime.Year, dateTime.Month, dateTime.Day, 23, 59, 59); 
     unavailableTimes.Add(new Available(previousTime, endDay)); 
0

Вы должны Concat свой DateTime в единый массив размерности:

 var minBorder = new DateTime(2015, 3, 16, 00, 00, 00); 
     var maxBorder = new DateTime(2015, 3, 16, 23, 59, 00); 

     var times = new List<DateTime>(); 
     times.Add(minBorder); 
     foreach (var at in availableTimes) { 
      times.Add(at.StartDate); 
      times.Add(at.EndDate); 
     } 
     times.Add(maxBorder); 

результат:

enter image description here

, а затем взять интервалы, нужно так:

public static IList<Available> Invert(IList<DateTime> input) { 
     var result = new List<Available>(); 
     for (var i = 0; i < input.Count; i += 2) { 
      result.Add(
       new Available(input[i], input[i + 1]) 
      ); 
     } 
     return result; 
    } 

enter image description here

1

Вы должны остерегаться первого и конечного временного диапазона для предельных случаев.

List<DateTimeRange> availableTimes = new List<DateTimeRange>() 
{ 
    new DateTimeRange(new DateTime(2015, 3, 16, 00, 00, 00), new DateTime(2015, 3, 16, 1, 00, 00)), 
    new DateTimeRange(new DateTime(2015, 3, 16, 08, 00, 00), new DateTime(2015, 3, 16, 10, 00, 00)), 
    new DateTimeRange(new DateTime(2015, 3, 16, 12, 00, 00), new DateTime(2015, 3, 16, 14, 00, 00)), 
    new DateTimeRange(new DateTime(2015, 3, 16, 15, 00, 00), new DateTime(2015, 3, 16, 16, 00, 00)), 
    new DateTimeRange(new DateTime(2015, 3, 16, 19, 00, 00), new DateTime(2015, 3, 16, 23, 59, 59)), 
}; 
var gap = GetGapsForDay(availableTimes); 




public IEnumerable<DateTimeRange> GetGapsForDay(List<DateTimeRange> ranges) 
{ 
    var start = ranges.First().StartDate.Date; 
    var end = ranges.First().StartDate.Date.AddDays(1).AddMinutes(-1); 

    foreach(var item in ranges.OrderBy(i => i.StartDate)) 
    { 
     if(start < item.StartDate) 
      yield return new DateTimeRange(start, item.StartDate); 

     start = item.EndDate; 
    } 
    if (ranges.Max(i => i.EndDate) < end) 
     yield return new DateTimeRange(start, end); 
} 
Смежные вопросы