Linq: rebuild hierarchical data from the flattened

2019-06-07 04:44发布

问题:

Disclaimer: I've been fighting against this problem since 2 days (I've read a lot of similar questions on SO).. so be patient, I'm missing something about the Group By with Linq and asking for help.

The Class Structure

Populating the sample data

I have a list of Macrotab. Each Macrotab object contains a list of Tab. Each Tab object inside with Slot inside.

List<MacroTab> hierarchaldata = CreateHierarchaldata();

*For keeping the question easy to read I've moved the CreateHierarchaldata, which populates a set of sample data, to .NetFiddle: https://dotnetfiddle.net/8mF1qI

Flattening

The following lines flattens this structure using Linq:

var flattenedList = (from macroTab in hierarchaldata
            from tab in macroTab.Tabs
            from slot in tab.Slots
            select new {macroTab.IDMacroTab, tab.IDTab, slot.IDSlot}).ToList();

Aggregate the data back to hierarchy

I've tried to get back to the original list using the the Linq Group By. This was my objective: to Aggregate the data for the Id of the MacroTab, Tabs and Slots and recreate the original list, but it doesn't work as expected**:

var antiflatten = from macrotab in flattenedList
            group macrotab by new {macrotab.IDMacroTab}
            into macrotabs
            let macrotabFirst = macrotabs.First()
            select new MacroTab
            {
                IDMacroTab = macrotabFirst.IDMacroTab,
                Tabs = (from macrotab in macrotabs
                    group macrotabs by new {macrotab.IDTab}
                    into tabs
                    let tabFirst = tabs.First()
                    select new Tab(){ HelperClass = tabFirst}).ToList()
            };

**The property HelperClass is just for debugging purpose, I hope it's not confusing, I've left it to explain the Visual Studio debugger's screenshot

Try it on Fiddler

回答1:

    var macroTabs = flattenedList
        .GroupBy(x => x.IDMacroTab)
        .Select((x) => new MacroTab
        {
            IDMacroTab = x.Key,
            Tabs = x.GroupBy(t => t.IDTab)
                    .Select(tx => new Tab {
                        IDTab = tx.Key,
                        Slots = tx.Select(s => new Slot {
                           IDSlot = s.IDSlot
                     }).ToList()
            }).ToList()
        }).ToList();