【问题标题】:Calculate average with linq without grouping [duplicate]用linq计算平均值而不分组[重复]
【发布时间】:2013-06-07 18:06:12
【问题描述】:

我有一个数据表,其中包含几列。 我想用 linq 计算这些的平均值,而不分组: 我试过这个:

dtPointCollFb.GroupBy(r => 1).Select(r => new
        {
            Plus100 = r.Average(item => item.PLUS100),
            Plus50 = r.Average(item => item.PLUS50),
            Plus10 = r.Average(item => item.PLUS10),
            Plus5 = r.Average(item => item.PLUS5),
            Plus1 = r.Average(item => item.PLUS1),
            NULLA = r.Average(item => item.NULLA)
        }).ToList()

当我计算总和时,这非常有效,但平均产生第一条记录值,而不是所有记录的平均值。 我认为这是不必要的: .GroupBy(r => 1) 因为我用常量分组。

但如果没有这个,我不能只对整个查询使用平均值,并且只能用于一列:

dtPointCollFb.Average(r => r.PLUS100)

那么有人可以提出一个简单的最佳实践解决方案吗? 如果可以使用方法语法,则不要查询。

我想要这样的东西:

dtPointCollFb.GroupBy(r => 0).Select(r => new
        {
            Plus100 = r.Sum(item => item.PLUS100) / dtPointCollFb.Rows.Count,
            Plus50 = r.Sum(item => item.PLUS50) / dtPointCollFb.Rows.Count,
            Plus10 = r.Sum(item => item.PLUS10) / dtPointCollFb.Rows.Count,
            Plus5 = r.Sum(item => item.PLUS5) / dtPointCollFb.Rows.Count,
            Plus1 = r.Sum(item => item.PLUS1) / dtPointCollFb.Rows.Count,
            NULLA = r.Sum(item => item.NULLA) / dtPointCollFb.Rows.Count
        }).ToList()

但使用更简单、更清洁的方式。这会正确地产生平均值。

【问题讨论】:

  • 不一样,但有建议分别计算平均值。
  • 仅作记录,我相信GroupBy 构造旨在强制在一次往返数据库中计算所有平均值。
  • 是的,你是对的,这将是最好的方法,因为我从 sql server 传输了很多数据。此模式旨在使用 linq 在 Web 服务器上进行多重聚合。我从同一个数据集合中计算出不同的东西。我可以在 5 个不同的 sql 查询中做到这一点。我不知道,也许会更好。

标签: c# linq


【解决方案1】:

Enumerable.Average 计算一个数字序列的平均值。因此,您需要为您需要的每个平均值投影(即Select)一列。

dtPointCollFb.Select(r => r.PLUS100).Average()

dtPointCollFb.Average(r => r.PLUS100)    

GroupBy 构建一个列表列表。在这种情况下,(外部)列表只有一个元素。 (因为您对原始列表中的所有元素任意使用相同的键)

所以你上面的内容可以很容易地写成:

var averages = new
{
    Plus100 = dtPointCollFb.Average(item => item.PLUS100),
    Plus50 = dtPointCollFb.Average(item => item.PLUS50),
    Plus10 = dtPointCollFb.Average(item => item.PLUS10),
    Plus5 = dtPointCollFb.Average(item => item.PLUS5),
    Plus1 = dtPointCollFb.Average(item => item.PLUS1),
    NULLA = dtPointCollFb.Average(item => item.NULLA)
};

做更多的事情需要定制的扩展功能(扩展IEnumerable<DataTableClass>)。

【讨论】:

    【解决方案2】:

    如果按照 Christopher 的建议,您想使用扩展,可以使用 Aggregate 方法。

    给定班级

    public class DataPoint
    {
        public double Plus100 { get; set; }
        public double Plus50 { get; set; }
        public double Plus10 { get; set; }
        public double Plus5 { get; set; }
        public double Plus1 { get; set; }
        public double NULLA { get; set; }
    }
    

    平均函数看起来像这样(手动计数避免了通过集合进行多次枚举):

    public static DataPoint Average(this IEnumerable<DataPoint> dataPoints)
    {
        var count = 0;
        var totals = dataPoints.Aggregate((lhs, rhs) =>
            {
                ++count;
                return new DataPoint
                    {
                        Plus100 = lhs.Plus100 + rhs.Plus100,
                        Plus50 = lhs.Plus50 + rhs.Plus50,
                        Plus10 = lhs.Plus10 + rhs.Plus10,
                        Plus5 = lhs.Plus5 + rhs.Plus5,
                        Plus1 = lhs.Plus1 + rhs.Plus1,
                        NULLA = lhs.NULLA + rhs.NULLA
                    };
            });
    
        return new DataPoint
            {
                Plus100 = totals.Plus100 / count,
                Plus50 = totals.Plus50 / count,
                Plus10 = totals.Plus10 / count,
                Plus5 = totals.Plus5 / count,
                Plus1 = totals.Plus1 / count,
                NULLA = totals.NULLA / count
            };
    }
    

    这种方法的优点是它只遍历一次集合。如果您有一个大型数据集,这将节省计算能力。如果您的数据点较少,我会使用 Christopher 的方法。

    【讨论】:

    • 好建议,我已经和你一样做了,但是我还没有做一个 linq 扩展方法,因为我只使用了一次这个计算。但我也做了一个嵌套类,就像你做的一样。谢谢!
    猜你喜欢
    • 1970-01-01
    • 2016-01-10
    • 1970-01-01
    • 2014-04-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-02-12
    相关资源
    最近更新 更多