запрос linq для получения максимального интервала времени

Я занимаюсь некоторыми базовыми материалами linq, но я не уверен, как это реализовать.

рассмотрим простой объект, подобный этому

public class Movement
{
    int areaId;
    DateTime startTime;
    DateTime endTime;
}

это представляет собой движение какого-либо предмета. startTime - это время, когда оно ввело область с помощью областиInd. endTime - время, когда оно покинуло эту область. У меня есть список из них для одного элемента в определенном порядке. Могут быть много разных движений для любой областиId, и ни один из них не перекрывается.

List<Movement> items = getSomeMovements();

Мне задан временной интервал, определяемый низким временем и высоким временем. низкое время меньше времени.

DateTime lowTime;
DateTime highTime;

Я хочу получить areaId, где элемент потратил больше всего времени в течение этого временного интервала. Я думаю, группа по области, найти общее время в каждом, и выберите наибольшее общее количество. Не уверен, как это сделать с Linq. Я ценю любую помощь.

c#,linq,c#-4.0,.net-4.0,

1

Ответов: 5


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

это можно сделать с помощью чистого 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()

это будет намного более чистым, если вы добавите пересечение в движение класса


0

Вы имеете в виду что-то вроде:

List<Movement> items = getSomeMovements();
Movement result = items.OrderByDescending(m => m.endTime - m.startTime).FirstOrDefault();

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
);

0

Используйте функцию пересечения Alireza, но тогда агрегация, а не упорядочение, будут более эффективными.

C #, LINQ, C # -4,0, .net-4.0,
Похожие вопросы