LINQ: события, сгруппированные по времени - PullRequest
2 голосов
/ 24 января 2012

Этот код ищет группы событий, которые произошли вместе.Макс 5 секунд между ними.И более 5 секунд между группами.

Обновление: Группа - это список дат времени.Одна группа содержит DateTimes, между которыми менее 5 секунд.DateTimes, которые произошли более чем за 5 секунд до следующей группы.

public static List<List<DateTime>> GetGroups(int count)
{
  var groups = new List<List<DateTime>>();
  groups.Add(new List<DateTime>());

  using (var db = new DbContainer())
  {
    foreach (var row in db.Table)
    {
      if (!groups.Last().Any() || (groups.Last().Any() && (row.Time - groups.Last().Last()).TotalSeconds <= 5))
      {
        groups.Last().Add(row.Time);
      }
      else if (groups.Count < count)
      {
        groups.Add(new List<DateTime>());
        groups.Last().Add(row.Time);
        continue;
      }

      if (groups.Count == count)
      {
        break;
      }
    }
  }

  return groups;
}

Можно ли реализовать один и тот же алгоритм в LINQ в одном или двух выражениях?

Ответы [ 2 ]

2 голосов
/ 24 января 2012

По сути, единственная сложная часть в вашем запросе, которую сложно выразить стандартными операторами LINQ to Objects, - это группирование элементов на основе того, насколько близко последовательных друг к другу.

Для этого я бы использовал блок итератора:

// Needs argument-checking, but you'll need another method to do it eagerly.
public static IEnumerable<List<T>> GroupByConsective<T>
      (this IEnumerable<T> source, Func<T, T, bool> prevNextPredicate)
{
    var currentGroup = new List<T>();

    foreach (var item in source)
    {
        if (!currentGroup.Any() || prevNextPredicate(currentGroup.Last(), item))
            currentGroup.Add(item); // Append: empty group or nearby elements.
        else
        {
            // The group is done: yield it out
            // and create a fresh group with the item.
            yield return currentGroup;
            currentGroup = new List<T> { item };
        }
    }

   // If the group still has items once the source is fully consumed,
   // we need to yield it out.
   if(currentGroup.Any())
     yield return currentGroup;
}

Для всего остального (проекция, ограничение числа групп, материализация в коллекцию) стандартный LINQ to Objects будет работать нормально. И так ваш запрос становится:

using (var db = new DbContainer())
{
   var groups = db.Table
                  .Select(row => row.Time)
                  .GroupByConsecutive((prev, next) => next.Subtract(prev)
                                                          .TotalSeconds <= 5)
                  .Take(count)
                  .ToList();

  // Use groups...

}
1 голос
/ 24 января 2012
.GroupBy(obj => long.Parse(obj.time.ToString("yyyyMMddHHmmss")) /5 )

используйте datetime.ToString () с форматом номера генерации для каждой секунды, затем / 5 для каждых 5 секунд

Редактировать: я не совсем уверен, что вы ищете, но я попробовал это и этоработает

var now = DateTime.Now;

            Console.WriteLine(now.ToString("yyyyMMddHHmmss"));

            Enumerable.Range(0, 57)
                .Select(offset => now.AddSeconds(offset))
                .GroupBy(interval => long.Parse(interval.ToString("yyyyMMddHHmmss")) / 5)
                .ToList()
                .ForEach(g => Console.WriteLine("{0}: {1} - {2}", g.Count(), g.Min().ToString("yyyyMMddHHmmss"), g.Max().ToString("yyyyMMddHHmmss")));

            Console.ReadKey();

Вот пример вывода

20120125144606
4: 20120125144606 - 20120125144609
5: 20120125144610 - 20120125144614
5: 20120125144615 - 20120125144619
5: 20120125144620 - 20120125144624
5: 20120125144625 - 20120125144629
5: 20120125144630 - 20120125144634
5: 20120125144635 - 20120125144639
5: 20120125144640 - 20120125144644
5: 20120125144645 - 20120125144649
5: 20120125144650 - 20120125144654
5: 20120125144655 - 20120125144659
3: 20120125144700 - 20120125144702

Дата-время выборки с интервалом 5 секунд.например, секунда из 10 - 14. Если вы хотите 11 - 15, вы можете добавить 1 секунду, прежде чем делить:)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...