开发者

LINQ get objects by date interval

I'm looking for a LINQ query that will select only those objects whose date interval is not higher than 20 seconds. For example:

AuthenticationEssay[] essays = new AuthenticationEssay[] {
    new AuthenticationEssay() { Date = DateTime.Now.AddSeconds(20), Success = false },
    new AuthenticationEssay() { Date = DateTime.Now.AddSeconds(24), Success = false },
开发者_JAVA技巧    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 }
};

I want to select only the first occurence of those objects whose date interval is not longer than 20 seconds against the next object. In this case, the query should return only the first 4 objects. Any idea? :(

UPDATE

Sorry, I forgot to mention that I'm sorting the array by descending order. So yes, the position in the array shouldn't have any effect on the query.


What about this?

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;

EDIT: Obviously you have to call First() in order to get only the first element of the sequence.

query.First();

EDIT 2: I have just read you are ordering your results descending. In this case the query will be slightly different:

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;


It ain't pretty, but here you go...

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

Does it have to be LINQ? I love LINQ, but I think something like this would be more readable...

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


It is probably possible to do it using built-in Linq operators, but in this case I think writing a specific method is easier. You could do something like that:

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

Of course it would be possible to make it more reusable, by making the method generic and passing a predicate as a parameter, but since it's a very specific requirement, I'm not sure it would be very useful...

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜