2013-03-14 7 views
-4

Скажем, у меня есть список LockedDate.Получить список дат в диапазоне дат

A LockedDate имеет DateTime и IsYearly bool. Если IsYearly истинно, то год не следует рассматривать, потому что это может быть любой год. Время никогда не следует рассматривать.

Ex: X-Mas, 25 декабря - ежегодно.

Теперь у меня есть список LockedDate.

Нет дубликатов.

Теперь мне нужна эта функция:

Эта функция будет делать: Если LockedDate НЕ ежегодно и на следующий день, месяц и год находятся в диапазоне от источника, добавить в список вернуться.

Если LockedDate IS ежегодно и его месяц/день попадают в диапазон, то добавьте новую дату для каждого года в диапазоне.

Скажите, что у меня есть 25 декабря с IsYearly как верно. Мой диапазон - 22 января 2013 года по 23 февраля 2015 года включительно. необходимо добавить 25 декабря 2013 года в качестве новой даты и 25 декабря 2014 года в качестве новой даты в список.

List<Date> GetDateRange(List<LockedDate> source, DateTime start, DateTime end) 
{ 


} 

Благодаря

Dec 25 Yearly -> Dec 25 2013, Dec 25 2014 
Dec 2, 2011 NOT Yearly -> Nothing 
March 25, 2013 => March 25 2013 
+0

«Мой диапазон от 22 января 2013 года до 23 февраля 2013 года включительно. Мне нужно будет добавить 25 декабря 2013 года в качестве новой даты и 25 декабря 2014 года в качестве новой даты в список». -Ты можешь объяснить это. – arunlalam

+1

Вы должны показывать данные образца и ожидаемый результат как минимум. Кроме того, в .NET нет 'Date', а' DateTime', вы имеете в виду это? –

+0

Да, я имею в виду DateTime, поэтому почему я сказал, что время не следует считать – user2043533

ответ

2

Это может дать вам хотя бы идею , это не тестируется на еще не все :

List<DateTime> GetDateRange(List<LockedDate> source, DateTime start, DateTime end) 
{ 
    if (start > end) 
     throw new ArgumentException("Start must be before end"); 

    var ts = end - start; 
    var dates = Enumerable.Range(0, ts.Days) 
     .Select(i => start.AddDays(i)) 
     .Where(d => source.Any(ld => ld.Date == d 
      || (ld.IsYearly && ld.Date.Month == d.Month && ld.Date.Day == d.Day))); 
    return dates.ToList(); 
} 

Update Вот демо с вашим образец данных, он работает: http://ideone.com/3KFi97

+0

Я думаю, это можно было бы назвать решением грубой силы :) – MarcinJuraszek

+0

@MarcinJuraszek: Я не сказал, что это самый эффективный подход, но он может быть одним из самых читаемых. Он может оптимизировать его, когда он действительно слишком медленный, и он подтвердил, что это на самом деле то, что он хочет. Кроме того, 'List ' кажется небольшим. –

+0

Я не говорю, что грубая сила плоха в каждой ситуации. Просто сказать, что это можно сделать более эффективным. – MarcinJuraszek

0

Этот код делает то, что вы хотите без использования Linq:

List<DateTime> GetDateRange(List<LockedDate> source, DateTime start, DateTime end) 
    { 
     List<DateTime> result = new List<DateTime>(); 

     foreach (LockedDate lockedDate in source) 
     { 
      if (!lockedDate.IsYearly && (lockedDate.Date >= start && lockedDate.Date <= end)) 
      { 
       result.Add(lockedDate.Date); 
      } 
      else if (lockedDate.IsYearly && (lockedDate.Date >= start && lockedDate.Date <= end)) 
      { 
       DateTime date = new DateTime(start.Year, lockedDate.Date.Month, lockedDate.Date.Day); 

       do 
       { 
        result.Add(date); 
        date = date.AddYears(1); 
       } while (date <= end); 
      } 
     } 

     return result; 
    } 

Убедитесь, чтобы спросить о части вы не понимаете, так что я могу подробно объяснить, но я думаю, что это довольно просто.

Этот код предполагает, что ваш класс LockedDate имеет свойство Date для объекта DateTime.

+0

Не совсем потому, что это: else if (lockedDate.IsYearly && (lockedDate.Date> = start && lockedDate.Date <= конец)) учитывает годовой год, когда на самом деле это должно быть больше похоже: за каждый день в диапазоне в качестве даты, если совпадение месяца и дня IsYearly, добавьте новую дату с месяцем, днем ​​и годом текущего дня, который вы итерируете. – user2043533

0

Если у вас есть класс LockedDate вроде этого:

public class LockedDate 
{ 
     public DateTime Date { get; set; } 
     public bool IsYearly { get; set; } 
     ... 
} 

Чем вы могли бы использовать этот код, чтобы получить ваши необходимые даты:

List<DateTime> GetDateRange(List<LockedDate> source, DateTime start, DateTime end) 
{ 

     List<DateTime> dt = new List<DateTime>(); 
     foreach(LockedDate d in source) 
     { 
      if(!d.IsYearly) 
      { 
        if(start<=d.Date && d.Date<=end) 
         dt.Add(d.Date); 
      } 
      else 
      { 
        for(DateTime i = new DateTime(start.Year,d.Date.Month,d.Date.Day);i<=new DateTime(end.Year,d.Date.Month,d.Date.Day);i=i.AddYears(1)) 
        { 
         dt.Add(i); 
        } 
      } 

     } 
     return dt; 
} 
+0

Это не сработает, потому что 'i.AddYears (1)' возвращает новый объект DateTime, который нигде не сохраняется. У вас там бесконечный цикл! – MarcinJuraszek

+0

@MarcinJuraszek Вы правы, обновили мой ответ, это была небольшая ошибка, я уверен, что вы не такой nitpicker, так как код вообще в порядке. –

0
var notYearly = lockDates.Where(d => !d.IsYearly && (d.Date.Date >= start && d.Date.Date <= end)).Select(d => d.Date); 

var years = ((end - start).Days/365) + 2; 
var startYear = start.Year; 

var yearly = lockDates.Where(d => d.IsYearly) 
         .SelectMany(d => Enumerable.Range(startYear, years) 
                .Select(e => new DateTime(e, d.Date.Month, d.Date.Day)) 
                .Where(i => i.Date >= start && i.Date <= end)); 

var allDates = notYearly.Union(yearly) 

должен быть более эффективным, чем просто перебор все дни между началом и окончанием и проверкой, если эта дата одобрена.

Смежные вопросы