任意时间跨度的Linq Gouping

时间:2012-03-14 18:58:23

标签: .net linq

我有一系列带时间戳的数据点,我希望按任意Timepsan值进行分组,

所以我想做一些像:

var span = Timespan.FromMinutes(5);
var grouped = from dataPoint in data
              group dataPoint by dataPoint.ThisISWhereIGetStuck(span) into argregateData
              select new {
                  Avg = argregateData.Average(x => x.Counter),
                  Span = argregateData.Key.SpanStartTime //or some such
              };                  

使用linq可以吗?

2 个答案:

答案 0 :(得分:0)

(假设我已经理解你了......)

嗯,一个简单的选择是:

var span = Timespan.FromMinutes(5);    
var grouped = from dataPoint in data
              group dataPoint by GroupTime(dataPoint.SomeDateTime, span)
                  into aggregateData
              select new {
                  Avg = aggregateData.Average(x => x.Counter),
                  Start = aggregateData.Key
              };


...

private static DateTime GroupTime(DateTime dateTime, TimeSpan span)
{
    long ticks = span.Ticks;
    return new DateTime((dateTime.Ticks / ticks) * ticks);
}

这比效率低,请注意 - 更有效的版本是:

var span = Timespan.FromMinutes(5);
long ticks = span.Ticks;
var grouped = from dataPoint in data
              group dataPoint by dataPoint.SomeDateTime.Ticks / ticks
                  into aggregateData
              select new {
                  Avg = aggregateData.Average(x => x.Counter),
                  Start = new DateTime(aggregateData.Key * ticks)
              };

如果按(例如)3分22秒进行分组,你会得到“有趣”的结果...基本上这段代码在DateTime.MinValue开始了...

答案 1 :(得分:0)

@Jon - 如果按任意间隔进行分组,我不确定结果是否很奇怪,是不是只是某些存储桶未被填充?如果您也捕获了桶号,您可以看到我的意思:

Module Module1
    Class DataPoint
        Property TimeStamp As DateTime
        Property Counter As Integer

        Public Overloads Function ToString() As String
            Return String.Format("{0} {1}", TimeStamp.ToString("yyyy-MM-dd HH:mm:ss"), Counter)
        End Function

        Public Sub New(timeStamp As DateTime, counter As Integer)
            Me.TimeStamp = timeStamp
            Me.Counter = counter
        End Sub
    End Class

    Sub Main()
        Dim data As New List(Of DataPoint)
        Dim baseTime = DateTime.UtcNow
        Dim rand As New Random

        ' make some random data, possibly with timestamps out of order
        For i = 0 To 29
            data.Add(New DataPoint(baseTime + TimeSpan.FromSeconds(i * 17 + rand.Next(0, 30)), rand.Next(0, 101)))
        Next

        ' show the data for inspection
        For Each d In data
            Console.WriteLine(d.ToString)
        Next

        ' make the buckets smaller than the expected interval between data
        Dim bucketSize = TimeSpan.FromMinutes(0.1)

        Dim grps = From datum In data
                   Group datum By bnr = (datum.TimeStamp.Ticks - baseTime.Ticks) \ bucketSize.Ticks
                   Into buckets = Group
                   Select Avg = buckets.Average(Function(x) x.Counter),
                    BucketStart = buckets.First,
                    BucketNumber = bnr,
                    Count = buckets.Count

        Console.WriteLine(grps.Count.ToString & " buckets.")

        ' show that not all buckets are filled/created
        For Each b In grps
            Console.WriteLine(String.Format("{0,3} {1,3} {2} {3}", b.BucketNumber, b.Count, b.BucketStart.TimeStamp.ToString("yyyy-MM-dd HH:mm:ss"), Math.Round(b.Avg, 2)))
        Next
        Console.ReadLine()
    End Sub
End Module