简体   繁体   English

使用Linq统计平均值

[英]Use Linq to statistics data with average

I have a class named HardwarePerformance contain these fields: time,cpuUsagePercent,memoryUsagePercent,diskUsage,diskRead,diskWrite,latency. 我有一个名为HardwarePerformance的类,其中包含以下字段:time,cpuUsagePercent,memoryUsagePercent,diskUsage,diskRead,diskWrite,latency。 I had fill a List object to contain the not statistics data. 我已经填充了一个List对象以包含非统计数据。 I need to calculating the average value for all these fields in a Linq command. 我需要在Linq命令中计算所有这些字段的平均值。 I don't know how to get the average value with Linq. 我不知道如何使用Linq获得平均值。 Follow is the code I wrote (It's incorrect of course). 遵循的是我编写的代码(当然这是不正确的)。

var _hardwarePerf = (from _stats in _statsList 
                    where _time>=DateTime.Parse("2012-04-04 00:00:00")
                        &&_time<=DateTime.Parse("2012-04-04 11:00:00") 
                    select new {
                           Latency = _stats.latency, 
                           CpuUsagePercent = _stats.cpuUsagePercent, 
                           MemoryUsagePercent = _stats.memoryUsagePercent, 
                           DiskUsage = _stats.diskUsage, DiskRead = _stats.diskRead, 
                           DiskWrite = _stats.diskWrite
                    }).Average(Latency => Latency.Latency);

The syntax of this code is correct. 该代码的语法正确。 But I want to calculating all the average value at the same time, how do I write my code? 但是我想同时计算所有平均值,如何编写代码?

There is no built-in method for this in LINQ. LINQ中没有内置方法。 If you don't mind that you will be iterating the collection several times, and assuming an anonymous object is okay for you, you can do something like this (where filteredStats contains the data you want to average, probably filtered by time): 如果您不介意要对集合进行多次迭代,并假设可以使用匿名对象,则可以执行以下操作(其中filteredStats包含要平均的数据,可能按时间过滤了):

var averages =
    new
    {
        Latency = filteredStats.Average(x => x.Latency),
        CpuUsagePercent = filteredStats.Average(x => x.CpuUsagePercent),
        …
    };

If that's not what you want, you will probably have to calculate the averages on your own. 如果这不是您想要的,则可能必须自己计算平均值。

The following calculates all the averages in one iteration, although it's a lot of code. 尽管有很多代码,但下面的代码可以一次迭代地计算所有平均值。

Note that I've assumed time is a property on your stats object, otherwise your select where time doesn't make much sense. 请注意,我假设time是您的stats对象的属性,否则select where time就没有多大意义了。

var _hardwareAccumulator =
    _statsList
        .Where(s =>
            s.time >= DateTime.Parse("2012-04-04 00:00:00") &&
            s.time <= DateTime.Parse("2012-04-04 11:00:00"))
        .Aggregate(
            new
            {
                count = 0,
                cpuUsagePercent = 0.0,
                memoryUsagePercent = 0.0,
                diskUsage = 0.0,
                diskRead = 0.0
            },
            (acc, s) =>
                new
                {
                    count = acc.count + 1,
                    cpuUsagePercent =
                        acc.cpuUsagePercent + s.cpuUsagePercent,
                    memoryUsagePercent =
                        acc.memoryUsagePercent + s.memoryUsagePercent,
                    diskUsage =
                        acc.diskUsage + s.diskUsage,
                    diskRead =
                        acc.diskRead + s.diskRead
                }
            );
var _hardwarePerf = new
{
    cpuUsagePercent =
        _hardwareAccumulator.cpuUsagePercent / _hardwareAccumulator.count,
    memoryUsagePercent =
        _hardwareAccumulator.memoryUsagePercent / _hardwareAccumulator.count,
    diskUsage =
        _hardwareAccumulator.diskUsage / _hardwareAccumulator.count,
    diskRead =
        _hardwareAccumulator.diskRead / _hardwareAccumulator.count
};

You either nee to do that in separate statements or you could do it in this not very intuitive way: 您可以在单独的语句中执行此操作,也可以通过这种不太直观的方式进行操作:

var averages = statsList.Where(s => s.time >= new DateTime(2012, 4, 4) && s.time <= new DateTime(2012, 4, 04, 11, 0, 0))
            .GroupBy(s => 1)
            .Select(grp => new
            {
                Latency = grp.Average(s => s.latency),
                CpuUsagePercent = grp.Average(s => s.cpuUsagePercent),
                MemoryUsagePercent = grp.Average(s => s.memoryUsagePercent),
                DiskUsage = grp.Average(s => s.diskUsage),
                DiskRead = grp.Average(s => s.diskRead),
                DiskWrite = grp.Average(s => s.diskWrite)
            }).FirstOrDefault();

Note that .GroupBy(s => 1) just to be able to calculate the average for each property. 请注意, .GroupBy(s => 1)只是为了能够计算每个属性的平均值。 Also note that i've removed the underlines from your property names and added time to your class. 另请注意,我已从您的媒体资源名称中删除了下划线,并为您的课程增加了时间

The other approach is easier to read: 另一种方法更容易阅读:

var theStats = statsList.Where(s => s.time >= new DateTime(2012, 4, 4) && s.time <= new DateTime(2012, 4, 04, 11, 0, 0));
var Latency = theStats.Average(s => s.latency);
var CpuUsagePercent = theStats.Average(s => s.cpuUsagePercent);
// ....

You can use "Group By" then you can use an average projection to calculate. 您可以使用“分组依据”,然后可以使用平均投影进行计算。

var query = from _stats in _statsList 
    group _stats by new {
               Latency = _stats.latency, 
               CpuUsagePercent = _stats.cpuUsagePercent, 
               MemoryUsagePercent = _stats.memoryUsagePercent, 
               DiskUsage = _stats.diskUsage, 
               DiskRead = _stats.diskRead, 
               DiskWrite = _stats.diskWrite

    } into myGroup
    select new {
        AverageVal = myGroup.Average(x => x.Value),
        CpuUsagePercent = myGroup.Key.CpuUsagePercent,
        ... // the rest of your projection
};

LINQ Average LINQ平均

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM