我一直在研究一些基本的linq,但我不确定如何实现这个。
考虑一个像这样的简单对象
public class Movement
{
int areaId;
DateTime startTime;
DateTime endTime;
}
这表示某个项目的移动。 startTime是它使用areaId进入区域的时间。 endTime是它离开该区域的时间。 我没有特定顺序的一个项目的列表。任何areaId都可以有许多不同的运动,并且没有时间重叠。
List<Movement> items = getSomeMovements();
给我一个时间间隔,由低时间和高时间定义。低时间不到很长时间。
DateTime lowTime;
DateTime highTime;
我希望在此时间间隔内获取项目花费最多时间的areaId。 我想按区域分组,找到每个区域的总时间,并选择最大的总数。不知道如何使用Linq这样做。我感谢任何帮助。
答案 0 :(得分:1)
这样的事情应该这样做:
var areaTime = from mov in items
where mov.startTime >= lowTime && mov.endTime <= highTime
group mov by mov.areaId into grp
select new
{
AreaID = grp.Key,
TimeSpent = grp.Sum(m => (m.endTime - m.startTime).TotalSeconds),
};
var areaSpentMostTimeIn = areaTime
.OrderByDescending(at => at.TimeSpent)
.FirstOrDefault();
答案 1 :(得分:1)
这可以用纯LINQ完成,但更整洁,首先声明两个函数:
TimeSpan Intersection(DateTime start, DateTime end, Movement movement)
{
DateTime t1 = start > movement.StartTime ? start : movement.StartTime;
DateTime t2 = end < movement.EndTime ? end : movemnt.EndTime;
return t1 < t2 ? t2 - t1 : TimeSpan.Empty;
}
然后使用:items.OrderByDescending(m => Intersection(lowTime, hightTime, m).FirstOrDefault()
如果将交点添加到班级移动
,这将更加清晰答案 2 :(得分:0)
你的意思是:
List<Movement> items = getSomeMovements();
Movement result = items.OrderByDescending(m => m.endTime - m.startTime).FirstOrDefault();
答案 3 :(得分:0)
使用Aggregate可以简单得多。完整的测试数据示例:
var now = DateTime.Now;
var movements = new []
{
new Movement { areaId = 1, startTime = now.AddDays(-10), endTime = now.AddDays(-9) },
new Movement { areaId = 2, startTime = now.AddDays(-8), endTime = now.AddDays(-7) },
new Movement { areaId = 3, startTime = now.AddDays(-5), endTime = now.AddDays(-2) },
new Movement { areaId = 4, startTime = now.AddDays(-2), endTime = now.AddDays(0) }
};
var longest = movements.Aggregate((m1, m2) =>
m1.endTime.Subtract(m1.startTime) > m2.endTime.Subtract(m2.startTime) ? m1 : m2
);
答案 4 :(得分:0)
使用Alireza的交叉功能,但聚合而不是订购会更有效率。