按运行时已知的多个键进行分组

时间:2014-11-12 14:27:57

标签: c# .net linq

我有一个telerik网格,我将一个对象列表数据绑定到一个页面上。用户可以在查看数据时根据自己的喜好对列进行分组。我正在编写一个函数来将此数据导出到Excel文档中,并希望保留用户在页面上的分组。我能够获取用户分组的对象属性的字符串名称。

我坚持的是如何在运行时进行分组。有很多这样的例子:Group by with multiple columns using lambda描述了如果你提前知道如何在编译期间按多个属性进行分组。但是,我不知道在运行期间要分组的内容。

是否有关于如何在运行时进行分组的建议?

3 个答案:

答案 0 :(得分:2)

您可能正在寻找类似this SO question答案的内容,特别是:

var myData = gridData.AsEnumerable()
                     .GroupBy(r => r, new MyDataComparer(keys))
                     .ToList();

internal class MyDataComparer : IEqualityComparer<MyDataType>
{
    private readonly string[] _keys;

    public MyDataComparer(string[] keys)
    {
        _keys = keys; // keep the keys to compare by.
    }

    public bool Equals(MyDataType x, MyDataType y)
    {
        // a simple implementation that checks if all the required fields 
        // match. This might need more work.
        bool areEqual = true;
        foreach (var key in _keys)
        {
            areEqual &= (x[key].Equals(y[key]));
        }
        return areEqual;
    }

    public int GetHashCode(DataRow obj)
    {
        // Add implementation here to create an aggregate hashcode.
    }
}    

答案 1 :(得分:0)

我会使用Dynamic Linq(http://weblogs.asp.net/scottgu/dynamic-linq-part-1-using-the-linq-dynamic-query-library

执行此操作

示例:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Dynamic; //have to install this via nuget or download it

public class Person {
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public DateTime DOB { get; set; }
}


class Program {
    static void Main(string[] args) {
        var peeps = new List<Person>{
            new Person(){ FirstName="Tim", LastName="Smith", DOB = DateTime.Now},
            new Person(){ FirstName="Tim", LastName="Smith", DOB = DateTime.Now.AddDays(1)},
            new Person(){ FirstName="Mike", LastName="Smith", DOB = DateTime.Now.AddDays(2)},
            new Person(){ FirstName="Frank", LastName="Jones", DOB = DateTime.Now.AddDays(3)},
        };

        var eq = peeps.GroupBy("new (LastName, FirstName)", "it").Select("new(it.Key as Key, it as People)"); ;
        foreach (dynamic el in eq) {
            Console.WriteLine(el.Key);
            foreach (var person in el.People as IEnumerable<Person>) {
                Console.WriteLine(person.LastName + " " + person.DOB);
            }
        }            
    }
}

答案 2 :(得分:0)

您尝试按运行时所拥有的特定媒体资源的名称进行分组。 除了固定在2个过滤器外,它与此类似。这只是你的另一个选择。 用linq pad来测试它。

过滤器的数量是固定的还是动态的?

void Main()
{
    var mySchool = new List<School>{
    new School{Student = "Student A", Teacher = "Teacher A", Subject = "Math", Grades = 80},
    new School{Student = "Student B", Teacher = "Teacher A", Subject = "Math", Grades = 65},
    new School{Student = "Student C", Teacher = "Teacher A", Subject = "Math", Grades = 95},
    new School{Student = "Student A", Teacher = "Teacher B", Subject = "History", Grades = 80},
    new School{Student = "Student B", Teacher = "Teacher B", Subject = "History", Grades = 100},
    new School{Student = "Student A", Teacher = "Teacher C", Subject = "English", Grades = 100},
    new School{Student = "Student C", Teacher = "Teacher B", Subject = "English", Grades = 100},
    new School{Student = "Student D", Teacher = "Teacher B", Subject = "English", Grades = 90},
    };


    GroupByFilters("Teacher", "Subject", mySchool);
    GroupByFilters("Subject", "Teacher", mySchool);
}



public void GroupByFilters(string filter1, string filter2, List<School> school)
{

    PropertyInfo prop1 = typeof(School).GetProperties()
                                      .Where(x => x.Name == filter1)
                                      .First();

    PropertyInfo prop2 = typeof(School).GetProperties()
                                      .Where(x => x.Name == filter2)
                                      .First();                                   
    var grouping = from s in school
                   group s by new {filter1 = prop1.GetValue(s), filter2 = prop2.GetValue(s)} into gr
                   select new {
                    Filter1 = gr.Key.filter1,
                    Filter2 = gr.Key.filter2,
                    TotalGrades = gr.Sum(x => x.Grades),
                    Count = gr.Count(),
                    Average = gr.Average(x => x.Grades)
                   };
    grouping.Dump(); // Linq pad specific 
}

// Define other methods and classes here
public class School{
    public string Student {get;set;}
    public string Teacher {get;set;}
    public string Subject {get;set;}
    public int Grades {get;set;}
}

Filter1 Filter2 TotalGrades Count Average

老师A Math 240 3 80

B老师历史180 2 90

老师C英语100 1 100

B老师英语190 2 95


Filter1 Filter2 TotalGrades Count Average

数学老师A 240 3 80

历史老师B 180 2 90

英语老师C 100 1 100

英语老师B 190 2 95