2011-01-14 63 views
6

我有我自己這樣做的方式,但我不認爲它是最好的,在C#尋找失蹤月

給定一個List<DateTime>,一個DateTime startDateDateTime endDate。你會如何返回一個新的List<DateTime>爲每startDateendDate這是間包括在原List<DateTime>包容startDateendDate的。

日期不保證是月份的開始,可以是月內的任何日期。

startDateendDate可能跨越多年。

返回的列表應包含每個月缺少的第一天。

謝謝,我希望它是有道理的。

+0

當你說「月」時,它是否包括年?您的描述中是2010年1月和2011年1月的不同月份嗎? – 2011-01-14 13:05:39

+0

你可以舉個例子嗎? – Pabuc 2011-01-14 13:05:49

+0

如果您將startDate指定爲1月15日,是否應包含1月份?既然你指定你想要那個月的第一個。 – 2011-01-14 14:13:41

回答

3
var list = new List<DateTime> 
    { 
     new DateTime(1231223423433132), 
     new DateTime(13223123132), 
     new DateTime(12333123132), 
     new DateTime(123345123132), 
     DateTime.Now, 
     new DateTime(5634534553) 
    }; 

var allYearMonthes = list.Select(o => 
          Eumerable.Range(1, 12) 
           .Select(q => new { o.Year, Month = q })) 
          .SelectMany(o => o); 

var enumerable = allYearMonthes.Except(list.Select(o => new { o.Year, o.Month })); 

var dateTimes = enumerable.Select(o => new DateTime(o.Year, o.Month, 1)); 

編輯: 對於那些誰感興趣的可能是完整的解決方案:

DateTime StartDate = DateTime.Now, EndDate = DateTime.Now.AddYears(5).AddMonths(2); 
var allYearMonthes = Enumerable.Range(StartDate.Year, EndDate.Year - StartDate.Year -1) 
           .Select(o => Enumerable.Range(1, 12) 
           .Select(q => new { Year = o, Month = q })) 
           .SelectMany(o => o); 

var enumerable = allYearMonthes.Except(list.Select(o => new { o.Year, o.Month })); 
var dateTimes = enumerable.Select(o => new DateTime(o.Year, o.Month, 1)); 
3

那麼,假設同月在不同年份被認爲是不同的:

private List<DateTime> GetUnincludedMonths(DateTime startDate, DateTime endDate, 
               IEnumerable<DateTime> dates) 
    { 
     var allMonths = new HashSet<Tuple<int, int>>(); //month, year 
     DateTime date = startDate; 
     while (date <= endDate) 
     { 
      allMonths.Add(Tuple.Create(date.Month, date.Year)); 
      date = date.AddMonths(1); 
     } 
     allMonths.Add(Tuple.Create(endDate.Month, endDate.Year)); 

     allMonths.ExceptWith(dates.Select(dt => Tuple.Create(dt.Month, dt.Year))); 
     return allMonths.Select(t => new DateTime(t.Item2, t.Item1, 1)).ToList(); 
    } 
+0

錯過這最後一個月,如果結束日期具有較低的日值比起始日期,即。 15月1日到2月1日,你增加一個月,到達2月15日,這是在結束日期之上。 – 2011-01-14 14:10:14

+0

像答案可惜我不能用4.0所以不必訪問元組 – 2011-01-14 14:11:00

-1
public IList<DateTime> GetMissingMonths(IList<DateTime> currentList, DateTime startDate, DateTime endDate) 
    { 
     // Create a list for the missing months 
     IList<DateTime> missingList = new List<DateTime>(); 

     // Select a startdate 
     DateTime testingDate = startDate; 

     // Begin by the month of startDate and ends with the month of endDate 
     // month of startDate and endDate included 
     while(testingDate <= endDate) 
     { 
      if (currentList.Count(m => m.Month == testingDate.Month && m.Year == testingDate.Year) == 0) 
      { 
       missingList.Add(new DateTime(testingDate.Year, testingDate.Month, 1)); 
      } 
      testingDate = testingDate.AddMonths(1); 
     } 
     return missingList; 
    } 
2

以下是我會做的:

static IEnumerable<DateTime> GetMissingMonths(IEnumerable<DateTime> currentDates, DateTime startDate, DateTime endDate) 
{ 
    var yearMonths = new HashSet<Tuple<int, int>>(currentDates.Select(d => Tuple.Create(d.Year, d.Month))); 
    DateTime current = new DateTime(startDate.Year, startDate.Month, 1); 
    if (current < startDate) 
     current = current.AddMonths(1); 
    while (current <= endDate) 
    { 
     if (!yearMonths.Contains(Tuple.Create(current.Year, current.Month))) 
     { 
      yield return current; 
     } 
     current = current.AddMonths(1); 
    } 
} 

編輯:如果你不能使用元組,你可以使用匿名類型來代替,用一個輔助方法來創建的HashSet:

static IEnumerable<DateTime> GetMissingMonths(IEnumerable<DateTime> currentDates, DateTime startDate, DateTime endDate) 
{ 
    var yearMonths = MakeHashSet(currentDates.Select(d => new { d.Year, d.Month })); 
    DateTime current = new DateTime(startDate.Year, startDate.Month, 1); 
    if (current < startDate) 
     current = current.AddMonths(1); 
    while (current <= endDate) 
    { 
     if (!yearMonths.Contains(new { current.Year, current.Month })) 
     { 
      yield return current; 
     } 
     current = current.AddMonths(1); 
    } 
} 

static HashSet<T> MakeHashSet<T>(IEnumerable<T> source) 
{ 
    return new HashSet<T>(source); 
} 

MakeHashSet方法可以讓你當T是匿名類型時,使用類型推斷來創建HashSet<T>

1

LINQPad木材加工解決方案:

void Main() 
{ 
    var dates = new List<DateTime> 
    { 
     new DateTime(2011, 1, 1), 
     new DateTime(2011, 3, 5), 
     new DateTime(2011, 7, 28), 
    }; 
    var startDate = new DateTime(2011, 1, 1); 
    var endDate = new DateTime(2012, 12, 31); 
    var existingMonths = 
     (from dt in dates 
     select dt.Year * 12 + dt.Month - 1).Distinct().ToArray(); 
    var missingMonths = 
     from ym in Enumerable.Range(
      startDate.Year * 12 + startDate.Month - 1, 
      (endDate.Year * 12 + endDate.Month) - (startDate.Year * 12 + startDate.Month) + 1) 
     where !existingMonths.Contains(ym) 
     select new DateTime(ym/12, ym % 12 + 1, 1); 
    missingMonths.Dump(); 
} 
0
static void Main(string[] args) 
     { 
      var days = (new string[] { "3/23/2000", "7/3/2004", "1/3/2004", "3/1/2011" }) 
         .Select(a => Convert.ToDateTime(a)); 

      days = days.Select(a => a.AddDays(1 - (a.Day))).Distinct(); 
      days = days.OrderBy(a => a); 

      var missingMonths = GetMissingMonths(days).ToList(); 
     } 

     private static IEnumerable<DateTime> GetMissingMonths(IEnumerable<DateTime> days) 
     { 
      DateTime previous = days.First(); 
      foreach (var current in days.Skip(1)) 
      { 
       int months = (current.Month - previous.Month) + 
            12 * (current.Year - previous.Year); 
       for (int i = 1; i < months; i++) 
       { 
        yield return previous.AddMonths(i); 
       } 
       previous = current; 
      } 
     } 
1
public IEnumerable<DateTime> GetMissingMonths(
    DateTime startDate, 
    DateTime endDate, 
    IEnumerable<DateTime> source) 
{ 
    IEnumerable<DateTime> sourceMonths = 
    source.Select(x => new DateTime(x.Year, x.Month, 1)) 
      .ToList() 
      .Distinct(); 
    return MonthsBetweenInclusive(startDate, endDate).Except(sourceMonths); 
} 

public IEnumerable<DateTime> MonthsBetweenInclusive(
    DateTime startDate, 
    DateTime endDate) 
{ 
    DateTime currentMonth = new DateTime(startDate.Year, startDate.Month, 1); 
    DateTime endMonth = new DateTime(endDate.Year, endDate.Month, 1); 

    while(currentMonth <= endMonth) 
    { 
    yield return currentMonth; 
    currentMonth = currentMonth.AddMonths(1); 
    } 
} 
0

感謝賈尼+1了他的想法。這一個是一行代碼:)

void Main() 
{ 

var list = new List<DateTime> 
{ 
    new DateTime(2005, 10, 11), 
    new DateTime(2009, 3, 4), 
    new DateTime(2010, 5, 8), 
    new DateTime(2010, 8, 10), 
    DateTime.Now, 
    new DateTime(2010, 4, 8) 
}; 

     var result= Enumerable.Range(list.Min (l => l.Year), list.Max (l => l.Year) - list.Min (l => l.Year)). 
      SelectMany (e => Enumerable.Range(1, 12).Select (en => new DateTime(e, en, 1))). 
      Except(list.Select(o => new DateTime(o.Year, o.Month, 1))). 
      Where (o => o.Date > list.Min (l => l.Date) && o.Date < list.Max (l => new DateTime(l.Year, l.Month, 1))); 

    } 
0

我會把我的帽子扔進去,因爲它很有趣。而且我沒有看到任何人將日期時間放在常規循環中,這是我永遠無法做到的,所以再次...有趣。

IEnumerable<DateTime> FindMissingMonths(DateTime startDate, DateTime endDate, IEnumerable<DateTime> inputs) 
{ 
    var allMonths = new List<DateTime>(); 
    for (DateTime d = startDate; d < endDate; d = d.AddMonths(1)) 
    { 
     allMonths.Add(new DateTime(d.Year, d.Month, 1)); 
    } 
    var usedMonths = (from d in inputs 
         select new DateTime(d.Year, d.Month, 1)).Distinct(); 
    return allMonths.Except(usedMonths); 
} 

修復了一個測試過的bug。