LINQ按某些值分组以形成树

Vin*_*dey 2 c# linq

我有一个看起来像这样的对象:

Tree {
    String Name;
    Int ID;
    List<SubObjects> SubObjects
}

SubObjects {
    int Level;
    string Name;
}
Run Code Online (Sandbox Code Playgroud)

我有以下形式的信息List<Output>在哪里Output是:

Output {
    String TreeName;
    Int TreeID;
    Int SubObjectLevel;
    String SubObjectName;
}
Run Code Online (Sandbox Code Playgroud)

本质上,树以以下格式表示

Tree1 TreeID1 Level1 SubObject1

Tree1 TreeID1 Level2 SubObject2

Tree1 TreeID1 Level3 SubObject3

Tree1 TreeID1 Level1 SubObject4

我想编写一个 LINQ 查询来填充 Tree,但我被困在 GroupBy。这是一个非常基本的问题,但我正在学习 LINQ,任何帮助将不胜感激。

谢谢!

编辑:

到目前为止,这是我的代码

var trees =
    from o in output
    select new Tree {
        Name = o.TreeName,
        ID   = o.TreeID,
        SubObjects = //somehow group them
    }
Run Code Online (Sandbox Code Playgroud)

我也试过

var trees =
    from o in output
    group o in o.TreeID into levels
    select new Tree {
        Name = //at this point o.TreeName is not available
    }
Run Code Online (Sandbox Code Playgroud)

Jer*_*all 5

因此,GroupBy采用一个平面列表并IGrouping根据定义的键生成一组较小的列表- 在这种情况下,您希望键是“树”,因为这是公共元素:

var sourceOutputs = <...get outputs list...>;

var query =
     // for each <Output> thingy...
     from outputThing in sourceOutputs
Run Code Online (Sandbox Code Playgroud)

在这里,我会暂停,因为你有很多选择这里-我们可以通过树ID,通过树名等组-我会在这两个组IDName

var query =
     // for each <Output> thingy...
     from outputThing in sourceOutputs
     // group them by Tree ID + Tree name
     group outputThing by 
         new { ID = outputThing.TreeID, Name = outputThing.TreeName } 
     into byTree
     // So now we can transform these groups of <Output> into a tree
     select new Tree
     {
         ID = byTree.Key.ID,
         Name = byTree.Key.Name,
         // And now the sub objects:
         // what 'byTree' actually is => a key (ID + name), 
         // and an enumerable of <Output> objects that match that key
         SubObjects = 
           (
               from matchedThingy in byTree
               select new SubObject() 
               { 
                   Level = matchedThingy.SubObjectLevel,
                   Name = matchedThingy.SubObjectName
                }
           ).ToList()
     };
Run Code Online (Sandbox Code Playgroud)