2012-01-24 43 views
2

此代碼搜索一起發生的事件組。 它們之間最多5秒。組間超過5秒鐘。LINQ:按時間分組的事件

更新:組是日期時間列表。一個組包含少於5秒的DateTime。發生超過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中的一個或兩個表達式中實現相同的算法嗎?

+0

看起來像代碼不會編譯。 – ChaosPandion

+1

@ M.Babcock - 'groups.Add(new List ());' – ChaosPandion

+0

@ChaosPandion - 是的,我修正了 – scazy

回答

2

本質上,關於您的查詢的唯一棘手的部分很難用標準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到對象將正常工作。所以您的查詢就會變成:

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... 

} 
+0

看起來很漂亮......並且工作可尊重......並且通用於序列。謝謝。 – scazy

1
.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秒前分開 :)

+0

除以五個作品對我的情況不正確。和EF4不支持'long.Parse'。 – scazy