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

时间:2018-02-21 23:27:47

标签: c# list data-structures struct

当前结构(由于系统要求无法更改)

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

示例语句列表

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

问题

我从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;
}

所以,从List<Statement>,我应该有一个 List<SectionCollection>,里面有一个 List<CategoryCollection>,里面有一个 List<Statement>

所以在上面的数据示例中,我会有

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

备注

A语句或类别在不同的部分可能是相同的并不是不可能的 - 这些仍然需要属于不同的SectionCollection s

尝试

我当前的尝试,一直有效,直到内部for循环最终抛出一个null异常。这是我一直盯着看的问题之一,所以我知道这个“解决方案”看起来多么混乱。

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});
    }
}

2 个答案:

答案 0 :(得分:2)

您收到空引用错误的原因是您没有初始化Categories中的SectionCollection列表。

更改:

SectionCollection thisSection = new SectionCollection();

要:

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

将修复错误。您也没有在任何地方捕获结果,如果您将代码更新到下面它应该可以工作:

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);
}

但是给类适当的构造函数和属性并在那里移动一些逻辑可能会更清晰一些:

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; }
    }
}

你最终会得到以下结构:

output structure

答案 1 :(得分:1)

使用以下命令创建新的SectionCollection对象:

SectionCollection thisSection = new SectionCollection();

但是你永远不会使用thisSection.categories初始化值new - 无论是在构造函数中还是在外部都没有显式。

因此,当您尝试在内循环中访问thisSection.categories.Add时,会生成异常。