запрос linq для получения наибольшего временного интервала - PullRequest
1 голос
/ 23 мая 2011

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

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

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

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

List<Movement> items = getSomeMovements();

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

DateTime lowTime;
DateTime highTime;

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

Ответы [ 5 ]

1 голос
/ 23 мая 2011

Примерно так должно быть, если я правильно понимаю ваш вопрос:

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 голос
/ 23 мая 2011

это может быть сделано с чистым 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 голосов
/ 24 мая 2011

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

0 голосов
/ 24 мая 2011

С 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 голосов
/ 23 мая 2011

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

List<Movement> items = getSomeMovements();
Movement result = items.OrderByDescending(m => m.endTime - m.startTime).FirstOrDefault();
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...