如何用linq在单一方法中制作聚合函数?[英] How to make aggregate function in single method using linq?

本文是小编为大家收集整理的关于如何用linq在单一方法中制作聚合函数?的处理/解决方法,可以参考本文帮助大家快速定位并解决问题,中文翻译不准确的可切换到English标签页查看源文。

问题描述

我有这样的课程

public class Student
{

    public int Id { get; set; }
    public string Name { get; set; }
    public string Gender { get; set; }
    public GRADE Grade { get; set; }
    public string Nationality { get; set; }
}
public enum GRADE
{
    A = 0,
    B = 1,
    C = 2,
    D = 3,
    E = 4
}

var list = new List<Student>();
list.Add(new Student() { Id = 1, Name = "Prasad", Gender = "M", Nationality = "India", Grade = GRADE.A });
list.Add(new Student() { Id = 2, Name = "Raja", Gender = "M", Nationality = "India", Grade = GRADE.B });
list.Add(new Student() { Id = 3, Name = "Hindu", Gender = "F", Nationality = "India", Grade = GRADE.A });
list.Add(new Student() { Id = 4, Name = "Hamed", Gender = "M", Nationality = "India", Grade = GRADE.C });
list.Add(new Student() { Id = 5, Name = "Priya", Gender = "F", Nationality = "India", Grade = GRADE.D });
list.Add(new Student() { Id = 6, Name = "Meera", Gender = "F", Nationality = "India", Grade = GRADE.B });

我得到了这样的解决方案,对于我想要编写一堆代码的每个表达式.和,avg,count等

linq表达式

//count
var c = (from x in list.GroupBy(k => k.Gender)
         select new
         {
             category = x.Key,
             Value = x.Count()
         }).ToList();

//sum
var s = (from x in list.GroupBy(k => k.Gender)
         select new
         {
             category = x.Key,
             Value = x.Sum(k => (int)k.Grade)
         }).ToList();

//avg
var a = (from x in list.GroupBy(k => k.Gender)
         select new
         {
             category = x.Key,
             Value = x.Average(k => (int)k.Grade)
         }).ToList();

我正在尝试基于聚合函数进行一个函数;它应该返回值,我试过我找不到它.

推荐答案

一个问题是,您拥有的一个问题是,所有三个聚合都没有相同的返回类型,也是使用函数,那么返回类型必须是对象,因为您返回匿名类型.

我最接近的我认为你想要的是这个;

步骤1:创建新类型;

public class AggregateValue<T>
{
    public string Category { get; set; }
    public T Value { get; set; }
}

步骤2:创建一个返回此类型集合的函数,并接受Func作为将计算不同聚合的参数;

    IEnumerable<AggregateValue<T>> GetAggregateValues<T>(List<Student> students, Func<IEnumerable<Student>, T> aggregateFunction)
    {
        return (from x in students.GroupBy(k => k.Gender)
                 select new AggregateValue<T>
                 {
                     Category = x.Key,
                     Value = aggregateFunction(x)
                 }).ToList();
    }

你可以像这样使用它;

        var list = new List<Student>();
        list.Add(new Student() { Id = 1, Name = "Prasad", Gender = "M", Nationality = "India", Grade = GRADE.A });
        list.Add(new Student() { Id = 2, Name = "Raja", Gender = "M", Nationality = "India", Grade = GRADE.B });
        list.Add(new Student() { Id = 3, Name = "Hindu", Gender = "F", Nationality = "India", Grade = GRADE.A });
        list.Add(new Student() { Id = 4, Name = "Hamed", Gender = "M", Nationality = "India", Grade = GRADE.C });
        list.Add(new Student() { Id = 5, Name = "Priya", Gender = "F", Nationality = "India", Grade = GRADE.D });
        list.Add(new Student() { Id = 6, Name = "Meera", Gender = "F", Nationality = "India", Grade = GRADE.B });

        var sumGrades = new Func<IEnumerable<Student>, int>(p => p.Sum(l => (int)l.Grade));
        var aveGrades = new Func<IEnumerable<Student>, double>(p => p.Average(k => (int)k.Grade));
        var count = new Func<IEnumerable<Student>, int>(p => p.Count());

        var c = GetAggregateValues(list, count);
        var s = GetAggregateValues(list, sumGrades);
        var a = GetAggregateValues(list, aveGrades);

其他推荐答案

您可以在一个语句中组合所有汇总:

var result = (from x in list.GroupBy(k => k.Gender)
    select new
    {
        category = x.Key,
        Count = x.Count(),
        Sum = x.Sum(k => (int)k.Grade),
        Average = x.Average(k => (int)k.Grade)
    }).ToList();

本文地址:https://www.itbaoku.cn/post/1557027.html

问题描述

I have class like this

public class Student
{

    public int Id { get; set; }
    public string Name { get; set; }
    public string Gender { get; set; }
    public GRADE Grade { get; set; }
    public string Nationality { get; set; }
}
public enum GRADE
{
    A = 0,
    B = 1,
    C = 2,
    D = 3,
    E = 4
}

var list = new List<Student>();
list.Add(new Student() { Id = 1, Name = "Prasad", Gender = "M", Nationality = "India", Grade = GRADE.A });
list.Add(new Student() { Id = 2, Name = "Raja", Gender = "M", Nationality = "India", Grade = GRADE.B });
list.Add(new Student() { Id = 3, Name = "Hindu", Gender = "F", Nationality = "India", Grade = GRADE.A });
list.Add(new Student() { Id = 4, Name = "Hamed", Gender = "M", Nationality = "India", Grade = GRADE.C });
list.Add(new Student() { Id = 5, Name = "Priya", Gender = "F", Nationality = "India", Grade = GRADE.D });
list.Add(new Student() { Id = 6, Name = "Meera", Gender = "F", Nationality = "India", Grade = GRADE.B });

I got the solution like this, For each expression i want to write bunch of code.. Sum,Avg,Count etc

Linq Expressions

//count
var c = (from x in list.GroupBy(k => k.Gender)
         select new
         {
             category = x.Key,
             Value = x.Count()
         }).ToList();

//sum
var s = (from x in list.GroupBy(k => k.Gender)
         select new
         {
             category = x.Key,
             Value = x.Sum(k => (int)k.Grade)
         }).ToList();

//avg
var a = (from x in list.GroupBy(k => k.Gender)
         select new
         {
             category = x.Key,
             Value = x.Average(k => (int)k.Grade)
         }).ToList();

I am trying to make one function, based on the aggregate function; it should return the value, I tried I could not find it.

推荐答案

One issue you have is that all three aggregates do not have the same return type, also if you use a function then the return type would have to be object because you are returning an anonymous type.

The closest I could get to what I think you want was this;

Step 1: create a new type;

public class AggregateValue<T>
{
    public string Category { get; set; }
    public T Value { get; set; }
}

Step 2: Create a function that returns a collection of this type and accepts a Func as a parameter that will calculate your different aggregates;

    IEnumerable<AggregateValue<T>> GetAggregateValues<T>(List<Student> students, Func<IEnumerable<Student>, T> aggregateFunction)
    {
        return (from x in students.GroupBy(k => k.Gender)
                 select new AggregateValue<T>
                 {
                     Category = x.Key,
                     Value = aggregateFunction(x)
                 }).ToList();
    }

You can use it like this;

        var list = new List<Student>();
        list.Add(new Student() { Id = 1, Name = "Prasad", Gender = "M", Nationality = "India", Grade = GRADE.A });
        list.Add(new Student() { Id = 2, Name = "Raja", Gender = "M", Nationality = "India", Grade = GRADE.B });
        list.Add(new Student() { Id = 3, Name = "Hindu", Gender = "F", Nationality = "India", Grade = GRADE.A });
        list.Add(new Student() { Id = 4, Name = "Hamed", Gender = "M", Nationality = "India", Grade = GRADE.C });
        list.Add(new Student() { Id = 5, Name = "Priya", Gender = "F", Nationality = "India", Grade = GRADE.D });
        list.Add(new Student() { Id = 6, Name = "Meera", Gender = "F", Nationality = "India", Grade = GRADE.B });

        var sumGrades = new Func<IEnumerable<Student>, int>(p => p.Sum(l => (int)l.Grade));
        var aveGrades = new Func<IEnumerable<Student>, double>(p => p.Average(k => (int)k.Grade));
        var count = new Func<IEnumerable<Student>, int>(p => p.Count());

        var c = GetAggregateValues(list, count);
        var s = GetAggregateValues(list, sumGrades);
        var a = GetAggregateValues(list, aveGrades);

其他推荐答案

You can combine all your aggregations in one statement:

var result = (from x in list.GroupBy(k => k.Gender)
    select new
    {
        category = x.Key,
        Count = x.Count(),
        Sum = x.Sum(k => (int)k.Grade),
        Average = x.Average(k => (int)k.Grade)
    }).ToList();