寻找失踪月
我有我自己这样做的方式,但我不认为它是最好的,在C#寻找失踪月
给定一个List<DateTime>
,一个DateTime startDate
和DateTime endDate
。你会如何返回一个新的List<DateTime>
为每月startDate
和endDate
这是间不包括在原List<DateTime>
包容startDate
和endDate
的。
日期不保证是月份的开始,可以是月内的任何日期。
startDate
和endDate
可能跨越多年。
返回的列表应包含每个月缺少的第一天。
谢谢,我希望它是有道理的。
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));
那么,假设同月在不同年份被认为是不同的:
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();
}
错过这最后一个月,如果结束日期具有较低的日值比起始日期,即。 15月1日到2月1日,你增加一个月,到达2月15日,这是在结束日期之上。 – 2011-01-14 14:10:14
像答案可惜我不能用4.0所以不必访问元组 – 2011-01-14 14:11:00
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;
}
以下是我会做的:
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>
。
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();
}
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;
}
}
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);
}
}
感谢贾尼+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)));
}
我会把我的帽子扔进去,因为它很有趣。而且我没有看到任何人将日期时间放在常规循环中,这是我永远无法做到的,所以再次...有趣。
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。
当你说“月”时,它是否包括年?您的描述中是2010年1月和2011年1月的不同月份吗? – 2011-01-14 13:05:39
你可以举个例子吗? – Pabuc 2011-01-14 13:05:49
如果您将startDate指定为1月15日,是否应包含1月份?既然你指定你想要那个月的第一个。 – 2011-01-14 14:13:41