LINQ получить объекты по интервалу дат - PullRequest
2 голосов
/ 16 апреля 2011

Я ищу запрос LINQ, который выберет только те объекты, чей интервал дат не превышает 20 секунд. Например:

AuthenticationEssay[] essays = new AuthenticationEssay[] {
    new AuthenticationEssay() { Date = DateTime.Now.AddSeconds(20), Success = false },
    new AuthenticationEssay() { Date = DateTime.Now.AddSeconds(24), Success = false },
    new AuthenticationEssay() { Date = DateTime.Now.AddSeconds(29), Success = false },
    new AuthenticationEssay() { Date = DateTime.Now.AddSeconds(38), Success = false },
    new AuthenticationEssay() { Date = DateTime.Now.AddSeconds(125), Success = false },
    new AuthenticationEssay() { Date = DateTime.Now.AddSeconds(347), Success = false },
    new AuthenticationEssay() { Date = DateTime.Now.AddSeconds(400), Success = false },
    new AuthenticationEssay() { Date = DateTime.Now.AddSeconds(422), Success = false },
    new AuthenticationEssay() { Date = DateTime.Now.AddSeconds(446), Success = false },
    new AuthenticationEssay() { Date = DateTime.Now.AddSeconds(467), Success = false }
};

Я хочу выбрать только первый вхождение тех объектов, чей интервал дат не превышает 20 секунд, относительно следующего объекта. В этом случае запрос должен вернуть только первые 4 объекта. Любая идея? (

UPDATE

Извините, я забыл упомянуть, что сортирую массив по убыванию. Так что да, позиция в массиве не должна влиять на запрос.

Ответы [ 3 ]

1 голос
/ 16 апреля 2011

Как насчет этого?

var query from i in Enumerable.Range(1, count - 1)
          let current = list[i]
          let previous = list[i - 1]
          // I see some empty positions in your example, nullability check
          where current != null && previous != null
          where (current.Date - previous.Date).TotalSeconds < 20
          select previous;

РЕДАКТИРОВАТЬ: Очевидно, что вам нужно вызвать First(), чтобы получить только первый элемент последовательности.

query.First();

РЕДАКТИРОВАТЬ 2: Я только что прочитал, что вы упорядочиваете результаты по убыванию.В этом случае запрос будет немного другим:

var query from i in Enumerable.Range(1, count - 1)
          let current = list[i]
          let previous = list[i - 1]
          // I see some empty positions in your example, nullability check
          where current != null && previous != null
          where (previous.Date - current.Date).TotalSeconds < 20
          select current;
0 голосов
/ 17 апреля 2011

Возможно, это можно сделать с помощью встроенных операторов Linq, но в этом случае я думаю, что написание конкретного метода проще. Вы могли бы сделать что-то подобное:

static IEnumerable<AuthenticationEssay> Filter(IEnumerable<AuthenticationEssay> list)
{
    AuthenticationEssay last = null;
    AuthenticationEssay previous = null;
    foreach(var item in list)
    {
        if (last == null)
        {
            // Always return the first item
            yield return item;
        }
        else if ((item.Date - last.Date).TotalSeconds >= 20)
        {
           yield return item;
        }

        previous = last;
        last = item;
    }
    if (previous != null && last != null && (last.Date - previous.Date).TotalSeconds <= 20)
       yield return last;
}

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

0 голосов
/ 16 апреля 2011

Это не красиво, но вот, пожалуйста ...

var result = Enumerable.Range(0, essays.Count() - 1)
    .Select(i => new {Essays1 = essays[i], Essays2 = essays[i + 1]})
    .Where(a => a.Essays2 != null)
    .Where(a => a.Essays2.Date - a.Essays1.Date < new TimeSpan(0, 0, 0, 20))
    .Select(a => a.Essays1);

Должно ли это быть LINQ? Я люблю LINQ, но думаю, что-то вроде этого было бы более читабельным ...

var result = new List<AuthenticationEssay>();
for (var i = 0; i < (essays.Count() - 1); i++)
{
    if (essays[i + 1] != null)
        if (essays[i + 1].Date - essays[i].Date < new TimeSpan(0, 0, 0, 20))
            result.Add(essays[i]);
}
...