简体   繁体   English

按属性对对象列表进行分组,拆分为多个列表。

[英]Grouping a List of objects by property, split into multiple lists.

Current Structure (Cannot change due to requirements of the system) 当前结构 (不能因系统要求而改变)

class Statement
{
    string section;
    string category;
    string statement;
}

Example Statement list 示例语句列表

section      category     statement
1            a            apple
1            a            banana
1            b            potato
2            c            car
2            c            bus
2            d            plane

Problem 问题

I start with a List<Statement> , and need to split them up based on Section, and then category into the following (or similar) structure 我从List<Statement> ,需要根据Section将它们拆分,然后将类别划分为以下(或类似)结构

struct SectionCollection
{
    string sectionName {get{return categories[0].section;}}
    List<CategoryCollection> categories;
}

struct CategoryCollection
{
    string categoryName {get{return statements[0].category;}}
    List<Statement> statements;
}

So, from the List<Statement> , I should have a List<SectionCollection> , which inside has a List<CategoryCollection> , which inside has a List<Statement> 所以,从List<Statement> ,我应该有一个List<SectionCollection> ,里面有一个List<CategoryCollection> ,里面有一个List<Statement>

So in the above data example, I would have 所以在上面的数据示例中,我会有

  • List<SectionCollection>
    • List<CategoryCollection> (Inside) List<CategoryCollection> (内部)
      • List<Statement> (Inside) List<Statement> (内部)

Notes 笔记

It's not impossible that A statement or a category might be the same in a different section - these still need to belong in different SectionCollection s A语句或类别在不同的部分中可能是相同的并不是不可能的 - 这些仍然需要属于不同的SectionCollection

Attempt 尝试

My current attempt, which works until a null exception is eventually thrown on the inner for loop. 我当前的尝试,直到最终在内部for循环上抛出null异常。 This is one of those problems I've been staring at for a while now, so I know how confused this 'solution' may seem. 这是我一直盯着看的问题之一,所以我知道这个“解决方案”看起来有多困惑。

var sections = statements.GroupBy(x => x.section).Select(y => y.ToList()).ToList();
foreach(var section in sections)
{
     SectionCollection thisSection = new SectionCollection();
     var categories = section.GroupBy(x => x.category).Select(y => y.ToList()).ToList();

    foreach(var category in categories)
    {
        thisSection.categories.Add(new CategoryCollection({statements = category});
    }
}

The reason you're getting a null reference error is because you're not initializing the Categories list in SectionCollection . 您获得空引用错误的原因是因为您没有在SectionCollection初始化Categories列表。

Changing: 更改:

SectionCollection thisSection = new SectionCollection();

To: 至:

SectionCollection thisSection = new SectionCollection() 
{ 
    Categories = new List<CategoryCollection>() 
};

Will fix the error. 将修复错误。 You're also not capturing the result anywhere, if you update your code to the below it should work: 你也没有在任何地方捕获结果,如果你将代码更新到下面它应该工作:

var sections = statements.GroupBy(x => x.Section).Select(y => y.ToList()).ToList();

var result = new List<SectionCollection>();

foreach (var section in sections)
{
    SectionCollection thisSection = new SectionCollection() { Categories = new List<CategoryCollection>() };

    var categories = section.GroupBy(x => x.Category).Select(y => y.ToList()).ToList();

    foreach (var category in categories)
    {
        thisSection.Categories.Add(new CategoryCollection { Statements = category });
    }

    result.Add(thisSection);
}

But it might be a bit cleaner to give classes proper constructors and properties and move some of the logic there: 但是给类适当的构造函数和属性并在那里移动一些逻辑可能会更清晰:

internal class Program
{
    static void Main(string[] args)
    {
        var statements = new List<Statement>()
        {
            new Statement(1, "a", "apple"),
            new Statement(1, "a", "banana"),
            new Statement(1, "b", "potato"),
            new Statement(2, "c", "car"),
            new Statement(2, "c", "bus"),
            new Statement(2, "d", "plane")
        };

        var sectionCollections = statements
            .GroupBy(s => s.Section)
            .Select(group => new SectionCollection(group.Key, statements))
            .ToList();
    }

    public class Statement
    {
        public Statement(int section, string category, string statementName)
        {
            Section = section;
            Category = category;
            StatementName = statementName;
        }

        public int Section { get; }

        public string Category { get; }

        public string StatementName { get; }
    }

    public class SectionCollection
    {
        public SectionCollection(int sectionName, List<Statement> statements)
        {
            SectionName = sectionName;

            Categories = statements
                .Where(s => s.Section == sectionName)
                .GroupBy(s => s.Category)
                .Select(group => new CategoryCollection(group.Key, group.ToList()))
                .ToList();
        }

        public int SectionName { get; }

        public List<CategoryCollection> Categories { get; }
    }

    public class CategoryCollection
    {
        public CategoryCollection(string categoryName, List<Statement> statements)
        {
            CategoryName = categoryName;
            Statements = statements;
        }

        public string CategoryName { get; }

        public List<Statement> Statements { get; }
    }
}

You'll end up with following structure: 你最终会得到以下结构:

输出结构

You create a new SectionCollection object with: 您创建一个新的SectionCollection对象:

SectionCollection thisSection = new SectionCollection();

But you never initialize the value thisSection.categories using new -- neither in the constructor or outside explicitly. 但是你永远不会使用new初始化thisSection.categories的值 - 既不在构造函数中也不在外部显式。

So when you attempt to access thisSection.categories.Add in your inner loop, you generate an exception. 因此,当您尝试在内部循环中访问thisSection.categories.Add时,会生成异常。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM