天天看点

Linq中Average,Sum等方法的使用解析背景一个例子

背景

最近在维护一个旧项目的时候遇到了大段的linq的代码,本来我可能就是这么静静的看着它了,可是天不从人愿,需求的变更刚刚需要处理这段代码。因为需要求和,去平均等相关的计算,所以开始一波度娘操作。嗯,相关的文章还是不少的,然而基本上就是举例子作为参考,有以类作为模板的数据源,也有datatable作为数据源的,但总感觉呼之欲出而不出。最后总算是按需求把求和等做了出来,于数就有了写点东西的想法。

一个例子

在具体说明怎么使用linq完成求和,平均等操作之前,我们先来把举例的相关类介绍一下,很简单的。我给的是班级和学生两个模板类,并以它们作为数据源基础使用。班级和学生是一对多的关系。具体的模板类如下

Class.cs

/// <summary>
    /// 班级模板
    /// </summary>
    public class Class
    {
        /// <summary>
        /// 编号
        /// </summary>
        public int Id { get; set; }
        /// <summary>
        /// 班级名称
        /// </summary>
        public string BName { get; set; }
    }
           

Students.cs

/// <summary>
    /// 学生模板
    /// </summary>
    public class Students
    {
        /// <summary>
        /// 编号
        /// </summary>
        public int Id { get; set; }
        /// <summary>
        /// 学生名称
        /// </summary>
        public string StudentName { get; set; }
        /// <summary>
        /// 性别,男和女
        /// </summary>
        public string Gender { get; set; }
        /// <summary>
        /// 年龄
        /// </summary>
        public int Age { get; set; }
        /// <summary>
        /// 班级编号
        /// </summary>
        public int BId { get; set; }
    }
           

然后我们来看下提供数据源的类,如下

GroupLinqSample.cs

public class GroupLinqSample
    {
        /// <summary>
        /// 得到班级数据源
        /// </summary>
        /// <returns></returns>
        public List<Class> GetClass()
        {
            return new List<Class>()
            {
                new Class(){ Id=1,BName="一班"},
                new Class(){ Id=2,BName="二班"},
                new Class(){ Id=3,BName="三班"},
            };
        }
        /// <summary>
        /// 得到学生数据源
        /// </summary>
        /// <returns></returns>
        public List<Students> GetStudents()
        {
            return new List<Students>()
            {
                new Students(){Id=1,StudentName="学生1",Age=19,Gender="男",BId=1},
                new Students(){Id=2,StudentName="学生2",Age=15,Gender="男",BId=1},
                new Students(){Id=3,StudentName="学生3",Age=17,Gender="女",BId=2},
                new Students(){Id=4,StudentName="学生4",Age=18,Gender="男",BId=3},
                new Students(){Id=5,StudentName="学生5",Age=18,Gender="女",BId=1},
                new Students(){Id=6,StudentName="学生6",Age=16,Gender="男",BId=3},
                new Students(){Id=7,StudentName="学生7",Age=19,Gender="女",BId=3},
                new Students(){Id=8,StudentName="学生8",Age=15,Gender="女",BId=1},
                new Students(){Id=9,StudentName="学生9",Age=18,Gender="男",BId=2},
                new Students(){Id=10,StudentName="学生10",Age=19,Gender="女",BId=2},
                new Students(){Id=11,StudentName="学生11",Age=17,Gender="男",BId=1},
                new Students(){Id=12,StudentName="学生12",Age=16,Gender="男",BId=3},
            };
        }
    }
           

具体的linq实现,我放在了一个控制台程序中,不多说,先上代码。

static void Main(string[] args)
{
    var lstCls = new GroupLinqSample().GetClass();
    var lstStu = new GroupLinqSample().GetStudents();

    var query = from s in lstCls
                join t in lstStu on s.Id equals t.BId
                group new { t.Age } by new { s.BName } into g
                select new
                {
                    ClassName = g.Key.BName,
                    AvgAge = g.Average(x => x.Age)
                };

    foreach (var item in query)
    {
        Console.WriteLine("班级:{0},平均年龄:{1}",item.ClassName,item.AvgAge);
    }
    
    Console.ReadKey();
}
           

从上面的代码中可以看出,我们是为了得到每个班级的平均年龄。而对于linq来说,想要使用sum等方法,就必须要分组(group)。所以我们需要把想要进行求和、取平均等操作的列放到group的后面,如group new { t.Age } ;而by后面放的是分组的列,如by new { s.BName } ,即说明是以班级名称来分组,对年龄进行求和、取平均的操作。当然不要忘记最后加上into g ,g是随便取的变量名称,因为这个在下面的select中需要使用。

现在来看select中内容,作为分组标准的班级名称字段(BName)必须使用 g.Key.BName的形式给出;而年龄的操作就简单了,直接进行求和、取平均等操作即可,如 g.Average(x => x.Age)。最后的输出不再多说了。

最后,让我们看看输出结果

Linq中Average,Sum等方法的使用解析背景一个例子