【问题标题】:Grouping a List of objects by property, split into multiple lists.按属性对对象列表进行分组,拆分为多个列表。
【发布时间】:2018-08-01 16:50:25
【问题描述】:

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

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&lt;Statement&gt;,我应该有一个 List&lt;SectionCollection&gt;,里面有一个 List&lt;CategoryCollection&gt;,里面有一个 List&lt;Statement&gt;

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

  • List&lt;SectionCollection&gt;
    • List&lt;CategoryCollection&gt;(内)
      • List&lt;Statement&gt;(内)

备注

一个语句或一个类别在不同的部分可能相同并非不可能——它们仍然需要属于不同的SectionCollections

尝试

我当前的尝试,直到最终在内部 for 循环中引发空异常为止。这是我一直在关注的问题之一,所以我知道这个“解决方案”看起来有多混乱。

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

【问题讨论】:

  • 我看不到 thisSection.categories 在哪里初始化为 new
  • @MFisherKDX 这可能只是问题所在。我现在正在研究这个问题,但我觉得我已经尝试过了,只是(愚蠢地)把它从我的例子中删除了已经提供了

标签: c# list data-structures struct


【解决方案1】:

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

变化:

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

你最终会得到以下结构:

【讨论】:

  • 非常感谢@RagtimeWilly,正如我在之前的一个 cmets/reponses 中所说,我已经尝试过初始化构造函数,但在某些情况下仍然面临空引用观点。最终,您在示例中设置 LINQ 表达式的方式为我指明了解决方案!我发誓每次使用 Linq 都能学到新东西!
  • 没问题,很高兴你把它整理好了。
【解决方案2】:

您创建一个新的SectionCollection 对象:

SectionCollection thisSection = new SectionCollection();

但是您永远不会使用 new 初始化值 thisSection.categories —— 无论是在构造函数中还是在外部显式地。

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

【讨论】:

  • 我正在进一步调查,但我不确定这是不是问题所在。 (我已经初始化了所有列表,并且我在上面提供的尝试仍然面临空引用)
  • 好的@Bejasc,继续编辑你的帖子,我会删除我的答案
猜你喜欢
  • 2022-01-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-06-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多