返回第一个连续的日期块



我希望建立一个已经回答的解决方案,围绕检查日期块是否是连续的,然后它会返回一个真/假布尔值。我发现可以很好地做到这一点的解决方案在这里找到,并且使用 LINQ 可以很好地确定真/假。 检查日期范围在 c# 中是否是连续的?。作为参考,下面是运行良好的 LINQ 语句。

public static bool IsContiguous(this IEnumerable<DateTime> dates)
{
var startDate = dates.FirstOrDefault();
if (startDate == null)
return true;
//.All() doesn't provide an indexed overload :(
return dates
.Select((d, i) => new { Date = d, Index = i })
.All(d => (d.Date - startDate).Days == d.Index);
}

我现在想尝试实现的是返回连续的第一个日期"块",例如,如果这些是输入到系统中的日期。

2019-12-24 
2019-12-25 
2019-12-26 
2020-01-04 
2020-01-05 
2020-01-10

我怎样才能拥有它,以便我可以返回第一个连续块中的第一个和最后一个日期,而不是返回布尔值。预期结果将是24日至26日。在此之后的一切都是多余的。

我实际上不确定如何开始这个解决方案,所以如果有人对从哪里开始或指出我有任何想法,我将不胜感激。

编辑:认为我可以以某种方式使用原始日期时间列表然后"删除"基于第一个日期的非连续日期?

List<DateTime> contiguousDates = new List<DateTime>
{
new DateTime(2019, 12, 24),
new DateTime(2019, 12, 25),
new DateTime(2019, 12, 26),
new DateTime(2020, 01, 04),
new DateTime(2020, 01, 05),
new DateTime(2020, 01, 10),
};

因此,如果以上是初始列表,那么 LINQ 查询是否可以删除不连续的记录,使列表仅保留 2019-12-24、2019-12-25、2019-12-26?

public static List<DateTime> FindFirstStreak(List<DateTime> dates)
{
if (dates.Count == 1)
return dates; // consider using .ToList() here to work on a copy
var ret = new List<DateTime>();
for (int i = 0; i < dates.Count - 1; i++)
{
var today = dates[i];
var tom = today.AddDays(1);
var next = dates[i + 1];
if (next == tom)
{
if (ret.Count == 0) ret.Add(today);
ret.Add(tom);
}
else
{
if (ret.Count > 0)
{
// check if streak has ended
if (next != tom)
return ret;
// optional: add ret, to result List<List<DateTime>> 
// and reset ret = new List<DateTime>(), to get all streaks
}
}
}
return ret;
}

试一试:

List<DateTime> contiguousDates = new List<DateTime>
{
new DateTime(2019, 12, 24),
new DateTime(2019, 12, 25),
new DateTime(2019, 12, 26),
new DateTime(2020, 01, 04),
new DateTime(2020, 01, 05),
new DateTime(2020, 01, 10),
};
var result = 
contiguousDates
.Skip(1)
.Zip(contiguousDates, (x1, x0) => new { x1, x0 })
.StartWith(new { x1 = contiguousDates.First(), x0 = contiguousDates.First().AddDays(-1.0) })
.TakeWhile(x => x.x1.Subtract(x.x0).TotalDays == 1.0)
.Select(x => x.x1)
.ToList();

这会产生:

2019/12/24 00:00:00 2019/12/25 00:00:00 2019/12/26 00:00:00

您可以将TakeWhile()与一些日期算术结合使用,如下所示:

List<DateTime> dates = new List<DateTime>
{
new DateTime(2019, 12, 24),
new DateTime(2019, 12, 25),
new DateTime(2019, 12, 26),
new DateTime(2020, 01, 04),
new DateTime(2020, 01, 05),
new DateTime(2020, 01, 10),
};
var initial = dates[0];
var contiguous = dates.TakeWhile((date, i) => date == initial.AddDays(i)).ToList();

如果你想要原始序列中包含的所有连续块,你可以用GroupBy()来获得一点创意:

var blocks = dates.Select((date, i) => new {date, i}).GroupBy(x => x.date.AddDays(-x.i))
.Select(group => group.ToList()).ToList();

最新更新