Depth-first flattened collection of an object hierarchy using LINQ

后端 未结 4 920
你的背包
你的背包 2020-12-21 05:13

I have an object hierarchy (MasterNode -> ChildNodes) where master and child nodes are of the same type, and there are only two levels (top level and children) like this (\'

相关标签:
4条回答
  • 2020-12-21 06:01

    Say, we have the following classes:

    public class MasterNode : ChildNode
    {
        public List<ChildNode> ChildNodes;
    }
    
    public class ChildNode
    {
        public string Value;
    }
    

    then

            List<MasterNode> list = new List<MasterNode>
            {
                new MasterNode
                {
                    Value="A", 
                    ChildNodes = new List<ChildNode>
                    {
                        new ChildNode{Value = "D"},
                        new ChildNode{Value = "E"},
                        new ChildNode{Value = "F"}
                    }
                },
                new MasterNode
                {
                    Value="B", 
                    ChildNodes = new List<ChildNode>
                    {                        
                        new ChildNode{Value = "G"}
                    }
                },
                new MasterNode
                {
                    Value="C", 
                    ChildNodes = new List<ChildNode>
                    {
                        new ChildNode{Value = "H"},
                        new ChildNode{Value = "I"}
                    }
                }
            };
    
            foreach (ChildNode c in list.SelectMany(l =>
                                    {
                                       List<ChildNode> result = l.ChildNodes.ToList();
                                       result.Insert(0, l);
                                       return result;
                                    }))
            {
                Console.WriteLine(c.Value);
            }
    
    0 讨论(0)
  • 2020-12-21 06:07

    If you have a class like below

    public class Node
    {
        public string Name;
        public List<Node> Children = new List<Node>();
    }
    

    your linq would be

     Func<IEnumerable<Node>, IEnumerable<Node>> Flatten = null;
     Flatten = coll => coll.SelectMany(n=>n.Concat(Flatten(n.Children)));
    

    Test Code:

    Node[] roots = new Node[]{ new Node(){Name="A"},new Node(){Name="B"},new Node(){Name="C"} };
    roots[0].Children.Add(new Node(){Name="D"});
    roots[0].Children.Add(new Node(){Name="E"});
    roots[0].Children.Add(new Node(){Name="F"});
    
    roots[1].Children.Add(new Node(){Name="G"});
    
    roots[2].Children.Add(new Node(){Name="H"});
    roots[2].Children.Add(new Node(){Name="I"});
    
    Func<IEnumerable<Node>, IEnumerable<Node>> Flatten = null;
    Flatten = coll => coll.SelectMany(n=>n.Concat(Flatten(n.Children)));
    
    var result = String.Join(",",Flatten(roots).Select(x=>x.Name));
    
    Console.WriteLine(result);
    
    0 讨论(0)
  • 2020-12-21 06:12

    If you need more than two hierarchy levels you can use the following extension method which goes recursively through your object graph:

    public static IEnumerable<T> Flat<T>(this IEnumerable<T> l, Func<T, IEnumerable<T>> f) =>
            l.SelectMany(i => new T[] { i }.Concat(f(i).Flat(f)));
    

    It flattens the given IEnumerable<T> with the use of a function that maps a T to an IEnumerable<T> describing the parent -> children relation of your data.

    The depth-first flattening is done by concatinating every element with its sub-tree and then joining them with SelectMany.

    You can use it like this:

    var flattened = Masternodes.Flat(c => c.children);
    
    0 讨论(0)
  • 2020-12-21 06:16

    Since you have only two levels, the following approach should work:

    var result = (from parent in masternodes
                  select new Node[] { parent }.Concat(parent.children)).SelectMany(i => i);
    

    First, it creates enumerables of the parent plus its children:

    [A, D, E, F]
    [B, G]
    [C, H]
    

    and then it flattens them with SelectMany.

    0 讨论(0)
提交回复
热议问题