按对象列表分组多个字段C#

时间:2015-03-11 14:55:13

标签: c# linq data-structures lambda

我有以下数据结构:

List<List<RecordItem>> combinedList = new List<List<RecordItem>>()
{
    new List<RecordItem>()
    {
        new RecordItem() { fieldName = "StudentId", value = "S1" },
        new RecordItem() { fieldName = "Maths", value = "90" },
        new RecordItem() { fieldName = "Term", value = "1" },
    },
    new List<RecordItem>()
    {
        new RecordItem() { fieldName = "StudentId", value = "S1" },
        new RecordItem() { fieldName = "Science", value = "70" },
        new RecordItem() { fieldName = "Term", value = "1" },
    }
}; 

我需要使用StudentId和Term对其进行分组,我能够按一个字段进行分组 - &gt; studentId(Credits:Enigmativity)但无法按多个字段分组(studentId和term)。 第一个问题是如何使用LINQ来获取另一个字段(term)?第二,如何为分组完成此代码。

List<List<RecordItem>> groupedList =
(
    from records in combinedList
    from student in records.Take(1) 
    from term   in records.Take(?) // how do I get the term which is the 4th element???
    let StudentId = student.value
    let Term = term.value
    let Subjects = records.Skip(1)
    group Subjects by new
    {
       StudentId,Term   
    into gss
    select new []
    {
        new RecordItem() { fieldName = "StudentId", value = gss.Key.StudentId },
        new RecordItem() { fieldName = "Term", value = gss.Key.Term },
    }.Concat(gss.SelectMany(x => x)).ToList()
).ToList();

3 个答案:

答案 0 :(得分:1)

我无法真正理解这里发生了什么以及你在选择什么,但这是语法上正确的代码:

static void Main(string[] args)
        {
            List<List<RecordItem>> combinedList = new List<List<RecordItem>>()
            {
                new List<RecordItem>()
                {
                    new RecordItem() { fieldName = "StudentId", value = "S1" },
                    new RecordItem() { fieldName = "Maths", value = "90" },
                    new RecordItem() { fieldName = "Term", value = "1" },
                },
                new List<RecordItem>()
                {
                    new RecordItem() { fieldName = "StudentId", value = "S1" },
                    new RecordItem() { fieldName = "Science", value = "70" },
                    new RecordItem() { fieldName = "Term", value = "1" },
                }
            };

            List<List<RecordItem>> groupedList =
            (
                from records in combinedList
                from student in records.Take(1)
                let StudentId = student.value
                let Term = records.ToArray().ElementAt(3).value
                let Subjects = records.Skip(1)
                group Subjects by new
                {
                    StudentId,
                    Term
                }
                    into gss
                    select new[]
                {
                    new RecordItem() { fieldName = "StudentId", value = gss.Key.StudentId },
                    new RecordItem() { fieldName = "Term", value = gss.Key.Term },
                }.Concat(gss.SelectMany(x => x)).ToList()
            ).ToList();
        }

答案 1 :(得分:1)

这就是你需要的:

List<List<RecordItem>> groupedList =
(
    from records in combinedList
    from student in records.Take(1)
    let StudentId = student.value
    from term in records.Skip(2).Take(1)
    let Term = term.value
    let Subjects = records.Skip(1).Take(1)
    group Subjects by new { StudentId, Term } into gss
    select new []
    {
        new RecordItem() { fieldName = "StudentId", value = gss.Key.StudentId },
        new RecordItem() { fieldName = "Term", value = gss.Key.Term },
    }.Concat(gss.SelectMany(x => x)).ToList()
).ToList();

尽管如此,这种数据结构在第二次会变得更糟。

答案 2 :(得分:0)

首先,您应该尝试使用比您拥有的更好的数据结构。说白了,使用List&gt;是蹩脚的,不得不依赖项目的顺序非常糟糕。做一些事情:将数据放在Dictionary<string,string>中,甚至更好地放在自己的自定义类中。像

这样的东西
public class MyData
{
    public string StudentId {get; set;}
    public string Maths {get; set;}
    public string Science {get; set;}
    public string Term {get; set;}
}

我不确定这是你想要的数据结构,我几乎可以肯定其中一些字段应该是string的其他字段,但你明白了。

根据您愿意实现的目标,您的数据结构合理,一切都会变得更加轻松。

现在,如果您拥有以前的数据结构,并希望将其投影到您刚创建的更好的数据结构,那就不难了。

投影到词典列表:

var dictionaries = groupedList.Select(l => 
    l.ToDictionary(
        item => item.fieldName ,
        item => item.value)
    ).ToList();

现在您可以再次投影到更好的数据结构:

var myTypedList = dictionaries.Select(d => new MyData
    {
        StudentId = d["StudentId"],
        Maths = d.ContainsKey("Maths") ? d["Maths"] : null,
        Science = d.ContainsKey("Science") ? d["Science"] : null,
        Term = d["Term"]
    }).ToList();

现在,您可以轻松完成所需的分组:

var myResults = myTypedList.GroupBy(val => new {val.StudentId, val.Term})
    .Select(group => new {
        StudentId = group.Key.StudentId,
        Term = group.Key.Term,
        Maths = group.First(v => v.Maths != null).Maths,
        Science = group.First(v => v.Science != null).Science
}).ToList();

请记住,当您为特定问题找到正确的数据结构时,大部分工作都将完成。尝试尽可能具体,它将使您的代码更容易编写和更容易阅读。试图变得“聪明”只与无意义的课程列表一起使用会让你无处可去。你在建模方面所做的工作是最重要的。