Search code examples
c#wpfdatagrid

C# Flaten a nested list to list of different object for display in a datagrid


I'm having an issue presenting my nested collection in a WPF Datagrid. bellow is the code that is giving me the desired result, but I wonder if it is possible to make it simpler?

public async Task LoadRecepi(short id)
    {
        Recepi = await _recepiDataService.Get(id);

        var flat = new List<FlatRecepi1>();
        foreach (var step in Recepi.Step)
        {
            flat.Add(new FlatRecepi1 { 
                RecepiId = step.RecepiId,
                StepId = step.SPTagId,
                Activity = step.Activity,
                PVTagName = step.PVTag.Name
            });  
            foreach (var node in step.Nodes)
            {
                flat.Add(new FlatRecepi1
                {
                    StepId = node.SPTagId,
                    SPTagName = node.SPTag.Name,
                    PVTagName = node.PVTag.Name
                });
            }
        }           

    }

thankyou so much for your help.

public class FlatRecepi1
{        
    public short RecepiId { get; set; }
    public short StepId { get; set; }
    public Activity Activity { get; set; }
    public short NodeId { get; set; }
    public string StepName { get; set; }
    public string PVTagName { get; set; }
    public string SPTagName { get; set; }
    public Operator Operator { get; set; }

}

Solution

  • You can use a combination of Enumerable.SelectMany and Enumerable.Prepend.

    The following code will project out each step's nodes into a collection of FlatRecepi1 and then prepend the FlatRecepi1 corresponding to the step at the start of the collection. Finally, the SelectMany flattens this "collection of collections" into a single list. This should give you the same ordering as the current code.

    var flat = Recepi.Step.SelectMany(step => 
       step.Nodes.Select(node => new FlatRecepi1 { 
           StepId = node.SPTagId, 
           SPTagName = node.SPTag.Name,
           PVTagName = node.PVTag.Name 
       }).Prepend(new FlatRecepi1 { 
           RecepiId = step.RecepiId,
           StepId = step.SPTagId,
           Activity = step.Activity,
           PVTagName = step.PVTag.Name,
       })
    ).ToList();
    

    If Prepend is not available to you because you are using an older framework, we can achieve the same with Enumerable.Concat:

    var flat = Recepi.Step.SelectMany(step => 
       new [] { 
          new FlatRecepi1 { 
            RecepiId = step.RecepiId,
            StepId = step.SPTagId,
            Activity = step.Activity,
            PVTagName = step.PVTag.Name,
          }
       }.Concat(
          step.Nodes.Select(node => new FlatRecepi1 { 
            StepId = node.SPTagId, 
            SPTagName = node.SPTag.Name,
            PVTagName = node.PVTag.Name 
          }) 
       )
    ).ToList();