我有以下类的对象列表:
public class CounterData
{
public DateTime counterTime { get; set; }
public int counterName { get; set; }
public int count { get; set; }
}
例如,我有{counterTime, counterName, count}
格式的以下数据列表:
{"Aug 8 2016 9:00AM","counter1",11}
{"Aug 8 2016 9:05AM","counter2",12}
{"Aug 8 2016 9:11AM","counter3",47}
{"Aug 8 2016 9:12AM","counter3",20}
{"Aug 8 2016 9:13AM","counter1",12}
{"Aug 8 2016 9:30AM","counter3",61}
{"Aug 8 2016 9:35AM","counter2",35}
{"Aug 8 2016 9:39AM","counter1",16}
{"Aug 8 2016 9:40AM","counter1",92}
{"Aug 8 2016 9:53AM","counter2",19}
我希望按每隔15分钟的时间聚合counterName
和counterTime
对计数器进行分组。对于上面的示例,结果列表应为:
{"Aug 8 2016 9:00AM","counter1",23}
{"Aug 8 2016 9:00AM","counter2",12}
{"Aug 8 2016 9:00AM","counter3",67}
{"Aug 8 2016 9:30AM","counter3",61}
{"Aug 8 2016 9:30AM","counter2",35}
{"Aug 8 2016 9:30AM","counter1",108}
{"Aug 8 2016 9:45AM","counter2",19}
从上午9点到9点15分,共有2个counter1
条目。因此count
值是条目的总和。其他柜台也是如此。
我们可以使用LINQ GroupBy来解决这个问题吗?如果是,那怎么样?
答案 0 :(得分:4)
这是一个将时间向舍入到最接近的15分钟的解决方案。它使用AddSeconds
来基本上摆脱DateTime
的秒部分,然后使用AddMinutes
var data = counters
.GroupBy(cd => new
{
Date = cd.counterTime.AddSeconds(-cd.counterTime.Second)
.AddMinutes(-cd.counterTime.Minute % 15),
CounterName = cd.counterName
})
.Select(g => new
{
Date = g.Key.Date,
CounterName = g.Key.CounterName,
SumCount = g.Sum(cd => cd.count)
});
来缩小分钟:
DbFunctions
但是,这不适用于LINQ to Entities(即实体框架),因此您需要稍微调整它以使用var data = counters
.GroupBy(cd => new
{
Date = DbFunctions.AddMinutes(
DbFunctions.AddSeconds(cd.counterTime, -cd.counterTime.Second),
-cd.counterTime.Minute % 15),
CounterName = cd.counterName
})
.Select(g => new
{
Date = g.Key.Date,
CounterName = g.Key.CounterName,
SumCount = g.Sum(cd => cd.count)
});
方法:
"resources": [
{
"type": "Microsoft.Search/searchServices",
"name": "[parameters('serviceName')]",
"apiVersion": "[parameters('serviceApiVersion')]",
"location": "[parameters('location')]",
"properties": {
"sku": {
"name": "[parameters('sku')]"
},
"replicaCount": 1,
"partitionCount": 1,
"hostingMode": "[parameters('hostingMode')]"
}
},
{
"type": "Microsoft.Search/searchServices",
"name": "[concat(parameters('serviceName'), 'secondary')]",
"apiVersion": "[parameters('serviceApiVersion')]",
"location": "[parameters('location')]",
"properties": {
"sku": {
"name": "[parameters('sku')]"
},
"replicaCount": 1,
"partitionCount": 1,
"hostingMode": "[parameters('hostingMode')]"
}
}]
答案 1 :(得分:1)
以下是将日期分组15分钟的示例。它可能效率不高,并且不适用于EF。但只要你只对LINQ做对象就应该没问题。
借助this question的扩展程序:
public static class DateTimeExtensions
{
public static DateTime RoundDown(this DateTime dt, TimeSpan d)
{
return new DateTime(((dt.Ticks + 1) / d.Ticks) * d.Ticks);
}
}
这就是分组:
var counter = new List<CounterData>
{
new CounterData {counterTime = DateTime.Now.AddMinutes(10), counterName = "counter1" },
new CounterData {counterTime = DateTime.Now.AddMinutes(15), counterName = "counter2" },
new CounterData {counterTime = DateTime.Now.AddMinutes(20), counterName = "counter3" },
new CounterData {counterTime = DateTime.Now.AddMinutes(25), counterName = "counter3" },
new CounterData {counterTime = DateTime.Now.AddMinutes(30), counterName = "counter1" },
new CounterData {counterTime = DateTime.Now.AddMinutes(35), counterName = "counter3" },
new CounterData {counterTime = DateTime.Now.AddMinutes(40), counterName = "counter2" },
new CounterData {counterTime = DateTime.Now.AddMinutes(45), counterName = "counter1" },
new CounterData {counterTime = DateTime.Now.AddMinutes(50), counterName = "counter1" },
new CounterData {counterTime = DateTime.Now.AddMinutes(55), counterName = "counter2" },
};
// Now it's grouped by date.
var groupedCounters = counter.GroupBy(x => x.counterTime.RoundDown(TimeSpan.FromMinutes(15))).Select(d => new { Date = d.Key, Counters = d.ToList() });
List<CounterData> result = new List<CounterData>();
// With foreach.
foreach (var groupedCounter in groupedCounters)
{
// Now we group by name as well.
var countersByName =
groupedCounter.Counters.GroupBy(x => x.counterName)
.Select(
x =>
new CounterData
{
count = x.Sum(item => item.Count),
counterTime = groupedCounter.Date,
counterName = x.Key
});
result.AddRange(countersByName);
}
// Or with LINQ.
foreach (var countersByName in groupedCounters.Select(groupedCounter => groupedCounter.Counters.GroupBy(x => x.counterName)
.Select(
x =>
new CounterData
{
count = x.Sum(item => item.Count),
counterTime = groupedCounter.Date,
counterName = x.Key
})))
{
result.AddRange(countersByName);
}