C# 在两个列表中查找重叠日期并返回重叠期间
我有两个包含UTC日期的列表。要确定列表是否包含重叠日期,我将执行以下操作:C# 在两个列表中查找重叠日期并返回重叠期间,c#,.net,linq,C#,.net,Linq,我有两个包含UTC日期的列表。要确定列表是否包含重叠日期,我将执行以下操作: list1.Where( x => list2.Any( y => x.StartDate < y.EndDate && y.StartDate < x.EndDate)); 我想返回: 1/1 10AM - 1/1 11AM 1/1 4PM - 1/1 5Pm 1/2 5AM - 1/2 8AM 日期永远不会为空 我认为取两个起点中的
list1.Where(
x =>
list2.Any(
y =>
x.StartDate < y.EndDate &&
y.StartDate < x.EndDate));
我想返回:
1/1 10AM - 1/1 11AM
1/1 4PM - 1/1 5Pm
1/2 5AM - 1/2 8AM
日期永远不会为空
我认为取两个起点中的最大值和两个终点中的最小值是可行的,但考虑到以下
日期范围
类,我不确定这在语法上会是什么样子:
public class DateRange
{
public DateRange(DateTime startDate, DateTime endDate)
{
StartDate = startDate;
EndDate = endDate;
}
public DateTime StartDate { get; set; }
public DateTime EndDate { get; set; }
}
以及以下简单的比较功能:
public static DateTime MinDate(DateTime first, DateTime second)
{
return first < second ? first : second;
}
public static DateTime MaxDate(DateTime first, DateTime second)
{
return first > second ? first : second;
}
请注意,如果对
列表进行排序,这种Linq
查询将是O(n2),这可以在O(n)中使用类似于的算法实现。这为您的示例提供了正确的答案
class DateSpan
{
public DateTime StartDate;
public DateTime EndDate;
public DateSpan(DateTime start, DateTime end)
{
StartDate = start;
EndDate = end;
}
public DateSpan(DateTime start, int duration)
{
StartDate = start;
EndDate = start.AddHours(duration);
}
}
public void TestStuff()
{
var dates1 = new System.Collections.Generic.List<DateSpan>();
dates1.Add(new DateSpan(new DateTime(2016, 1, 1, 5, 0, 0), 17));
dates1.Add(new DateSpan(new DateTime(2016, 1, 2, 4, 0, 0), 4));
var dates2 = new System.Collections.Generic.List<DateSpan>();
dates2.Add(new DateSpan(new DateTime(2016, 1, 1, 10, 0, 0), 1));
dates2.Add(new DateSpan(new DateTime(2016, 1, 1, 16, 0, 0), 1 ));
dates2.Add(new DateSpan(new DateTime(2016, 1, 2, 5,0,0), 17 ));
var e = dates1.SelectMany((DateSpan x) =>
{
var result = new List<DateSpan>();
foreach (var o in dates2.Where(y => x.StartDate < y.StartDate && y.StartDate < x.EndDate).ToList())
{
result.Add(new DateSpan(new DateTime(Math.Max(x.StartDate.Ticks, o.StartDate.Ticks)), new DateTime(Math.Min(x.EndDate.Ticks, o.EndDate.Ticks))));
}
return result;
});
//var d = dates1.Where(x => dates2.Any(y => x.StartDate < y.StartDate && y.StartDate < x.EndDate)).ToList();
}
class日期跨度
{
公共日期时间开始日期;
公共日期时间结束日期;
公共日期跨度(日期时间开始,日期时间结束)
{
开始日期=开始;
结束日期=结束;
}
公共日期跨度(日期时间开始,整数持续时间)
{
开始日期=开始;
EndDate=开始时长(持续时间);
}
}
公共void TestStuff()
{
var dates1=new System.Collections.Generic.List();
日期1.添加(新的日期跨度(新的日期时间(2016,1,1,5,0,0,17));
日期1.添加(新的日期跨度(新的日期时间(2016,1,2,4,0,0,4));
var dates2=new System.Collections.Generic.List();
dates2.Add(新的日期跨度(新的日期时间(2016,1,1,10,0,0,1));
dates2.Add(新的日期跨度(新的日期时间(2016,1,1,16,0,0,1));
dates2.Add(新的日期跨度(新的日期时间(2016,1,2,5,0,0,17));
变量e=日期1。选择多个((日期跨度x)=>
{
var result=新列表();
foreach(dates2.Where(y=>x.StartDatedates2.Any(y=>x.StartDate
下面是基于您的逻辑构建的代码。我没有使用where
和任何组合,而是使用笛卡尔积,它更清楚地表示了您的逻辑。只需将Min
和Max
功能组合起来,即可满足您的需求
struct DateRange {
public DateTime StartDate, EndDate;
public override string ToString() {
return $"{StartDate} - {EndDate}";
}
};
static void Main(string[] args) {
var list1 = new List<DateRange>() {
new DateRange() { StartDate = DateTime.Parse("1/1/2016 5AM"), EndDate = DateTime.Parse("1/1/2016 10PM") },
new DateRange() { StartDate = DateTime.Parse("1/2/2016 4AM"), EndDate = DateTime.Parse("1/2/2016 8AM") }
};
var list2 = new List<DateRange>() {
new DateRange() { StartDate = DateTime.Parse("1/1/2016 10AM"), EndDate = DateTime.Parse("1/1/2016 11AM")},
new DateRange() { StartDate = DateTime.Parse("1/1/2016 4PM"), EndDate = DateTime.Parse("1/1/2016 5PM")},
new DateRange() { StartDate = DateTime.Parse("1/2/2016 5AM"), EndDate = DateTime.Parse("1/2/2016 10PM")}
};
var overlapList = from outer in list1
from inner in list2
where outer.StartDate < inner.EndDate && inner.StartDate < outer.EndDate
select new DateRange() {
StartDate = new DateTime(Math.Max(outer.StartDate.Ticks, inner.StartDate.Ticks)),
EndDate = new DateTime(Math.Min(outer.EndDate.Ticks, inner.EndDate.Ticks))
};
}
struct-DateRange{
公共日期时间开始日期,结束日期;
公共重写字符串ToString(){
返回$“{StartDate}-{EndDate}”;
}
};
静态void Main(字符串[]参数){
var list1=新列表(){
new DateRange(){StartDate=DateTime.Parse(“1/1/2016 5AM”),EndDate=DateTime.Parse(“1/1/2016 10PM”),
new DateRange(){StartDate=DateTime.Parse(“1/2/2016 4AM”),EndDate=DateTime.Parse(“1/2/2016 8AM”)}
};
var list2=新列表(){
new DateRange(){StartDate=DateTime.Parse(“1/1/2016上午10点”),EndDate=DateTime.Parse(“1/1/2016上午11点”),
new DateRange(){StartDate=DateTime.Parse(“2016年1月1日下午4点”),EndDate=DateTime.Parse(“2016年1月1日下午5点”),
new DateRange(){StartDate=DateTime.Parse(“1/2/2016 5AM”),EndDate=DateTime.Parse(“1/2/2016 10PM”)}
};
var overlapList=来自列表1中的外部
从列表2中的内部
其中outer.StartDate
为了使代码更具可读性,我使用了let
子句:
var q =
from x in list1
from y in list2
let start = Max(x.StartDate, y.StartDate)
let end = Min(x.EndDate, y.EndDate)
where start < end
select new { start, end };
foreach (var item in q)
{
Console.WriteLine($"{item.start}-{item.end}");
}
var q=
从列表1中的x开始
来自列表2中的y
让开始=最大值(x.开始日期,y.开始日期)
设end=Min(x.EndDate,y.EndDate)
从哪里开始
选择新{开始,结束};
foreach(q中的var项目)
{
WriteLine($“{item.start}-{item.end}”);
}
Max
和Min
方法来自。因此,结果中的最后一项是1/2 5AM-1/2 8AM,而不是1/2 5AM-1/2 10pm?请更正到8AM,因为它们在8AM后不再重叠。这是一个非常优雅的解决方案
struct DateRange {
public DateTime StartDate, EndDate;
public override string ToString() {
return $"{StartDate} - {EndDate}";
}
};
static void Main(string[] args) {
var list1 = new List<DateRange>() {
new DateRange() { StartDate = DateTime.Parse("1/1/2016 5AM"), EndDate = DateTime.Parse("1/1/2016 10PM") },
new DateRange() { StartDate = DateTime.Parse("1/2/2016 4AM"), EndDate = DateTime.Parse("1/2/2016 8AM") }
};
var list2 = new List<DateRange>() {
new DateRange() { StartDate = DateTime.Parse("1/1/2016 10AM"), EndDate = DateTime.Parse("1/1/2016 11AM")},
new DateRange() { StartDate = DateTime.Parse("1/1/2016 4PM"), EndDate = DateTime.Parse("1/1/2016 5PM")},
new DateRange() { StartDate = DateTime.Parse("1/2/2016 5AM"), EndDate = DateTime.Parse("1/2/2016 10PM")}
};
var overlapList = from outer in list1
from inner in list2
where outer.StartDate < inner.EndDate && inner.StartDate < outer.EndDate
select new DateRange() {
StartDate = new DateTime(Math.Max(outer.StartDate.Ticks, inner.StartDate.Ticks)),
EndDate = new DateTime(Math.Min(outer.EndDate.Ticks, inner.EndDate.Ticks))
};
}
var q =
from x in list1
from y in list2
let start = Max(x.StartDate, y.StartDate)
let end = Min(x.EndDate, y.EndDate)
where start < end
select new { start, end };
foreach (var item in q)
{
Console.WriteLine($"{item.start}-{item.end}");
}