提问人:Sara tabaghchi 提问时间:9/18/2023 最后编辑:EnigmativitySara tabaghchi 更新时间:9/18/2023 访问量:90
如何在 c 中将日期列表转换为日期范围列表#
How Convert Date Lists to DateRanges List in c#
问:
这种区别怎么可能:List<DateTime>
List<List<DateTime>>
1
例如,List 是
var list = new List<DateTime>()
{
new DateTime(2023, 05, 02),
new DateTime(2023, 05, 03),
new DateTime(2023, 05, 04),
new DateTime(2023, 05, 10),
new DateTime(2023, 05, 11),
new DateTime(2023, 05, 20),
};
我希望我的方法返回此列表
{
2023-05-02,
2023-05-03,
2023-05-04
},
{
2023-05-10,
2023-05-11
},
{
2023-05-20
}
答:
1赞
Dmitry Bychenko
9/18/2023
#1
您可以尝试循环并在 Linq 的帮助下构建答案,例如
using System.Linq;
...
private static List<List<DateTime>> Solve(IEnumerable<DateTime> source) {
List<List<DateTime>> result = new();
if (source is null)
return result;
foreach (var date in source.OrderBy(item => item))
if (result.Count > 0 && result.Last().Last().AddDays(1) == date)
result.Last().Add(date);
else
result.Add(new List<DateTime>() { date });
return result;
}
评论
1赞
Tim Schmelter
9/18/2023
而不是我会使用 .然后,如果他们有时间部分,它也可以工作。result.Last().Last().AddDays(1) == date
dt - result.Last().Last()).TotalDays > 1
2赞
Enigmativity
9/18/2023
#2
下面是 LINQ 的答案:
List<List<DateTime>> result =
list
.Skip(1)
.Aggregate(
new[] { list.Take(1).ToList() }.ToList(),
(a, x) =>
{
if (x.Subtract(a.Last().Last()).Days != 1)
{
a.Add(new List<DateTime>());
}
a.Last().Add(x);
return a;
});
这给出了:
注意:这假设已经订购(根据问题中的列表)。list
或者作为一种方便的扩展方法:
public static List<List<T>> Aggregate<T>(this IEnumerable<T> source, Func<List<List<T>>, T, bool> isCurrent)
{
List<List<T>> result = new() { new List<T>() };
using (var e = source.GetEnumerator())
{
if (e.MoveNext())
{
result.Last().Add(e.Current);
while (e.MoveNext())
{
if (!isCurrent(result, e.Current))
{
result.Add(new List<T>());
}
result.Last().Add(e.Current);
}
}
return result;
}
}
现在是:
List<List<DateTime>> result =
list
.Aggregate((a, x) => x.Subtract(a.Last().Last()).Days == 1);
评论
0赞
Enigmativity
9/18/2023
@Ralf - 是的,所有答案都经过了充分测试。
0赞
Charlieface
9/18/2023
var e
需要一个.还不如留在本地。另外为什么不是外部列表?using
result.Last()
yield return
0赞
Enigmativity
9/18/2023
@Charlieface - 我不喜欢在底层源可能很热时返回半暴露的枚举对象。
0赞
Orion
9/18/2023
#3
循环遍历日期并检查当前日期是否与上一个日期相差不到 1 天。如果是,则将其添加到当前列表中,否则开始一个新列表。
private List<List<DateTime>> GetListsOfConsecutiveDates(List<DateTime> dates)
{
var result = new List<List<DateTime>>();
var currentList = new List<DateTime>();
var previousDate = dates.First();
currentList.Add(previousDate);
foreach (var date in dates.Skip(1))
{
if (date - previousDate <= TimeSpan.FromDays(1))
{
currentList.Add(date);
}
else
{
result.Add(currentList);
currentList = new List<DateTime> { date };
}
previousDate = date;
}
result.Add(currentList);
return result;
}
1赞
Tim Schmelter
9/18/2023
#4
如果您的逻辑需要访问下一个或上一个项目,我不会使用 LINQ。简单易读且高效。如果他们有时间,以下工作也有效:foreach
List<List<DateTime>> result = new();
foreach (DateTime dt in list.OrderBy(d => d))// omit OrderBy if the list is already sorted
{
if(result.Count == 0 || (dt - result[^1].Last()).TotalDays > 1)
{
result.Add(new List<DateTime>{dt});
}
else
{
result[^1].Add(dt);
}
}
评论
0赞
Sara tabaghchi
9/18/2023
索引运算符在 C#7.3 中不起作用
1赞
Tim Schmelter
9/18/2023
@Saratabaghchi:然后使用 LINQ 或索引器。 检查序列是否具有索引器并使用该索引器,因此它也很有效。Last
result[result.Count-1]
Enumerable.Last
0赞
Charlieface
9/18/2023
#5
这是一个完全流媒体的版本。任何地方都没有创建列表,整个事情使用 .IEnumerable
它假设原始源是(以便我们可以使用有效的算法),并且它已经排序。List<T>
SkipTake
public static IEnumerable<IEnumerable<T>> GroupUp<T>(this List<T> source, Func<T, T, bool> isSameGroupFunc)
{
for (var start = 0; start < source.Count; start++)
{
var end = start;
while (end + 1 < source.Count)
{
if (!isSameGroupFunc(source[end], source[end + 1]))
break;
end++;
}
yield return SkipTake(source, start, end + 1);
start = end;
}
}
private static IEnumerable<T> SkipTake<T>(List<T> source, int start, int count)
{
for (var i = start; i < count; i++)
yield return source[i];
}
你像这样使用它:
var results = list.GroupUp((a, b) => a.AddDays(1) >= b);
上一个:基于日期范围的 SQL 查询
下一个:如何在猫鼬中查询日期
评论