深度优先扁平使用LINQ对象分层结构的集(Depth-first flattened collect

2019-06-27 17:16发布

我有一个对象的层次结构(MasterNode - >的childNodes),其中主站和子节点都是同一类型的,而且只有两个级别(最高级别和儿童)这样的(“A”是d,E和F的父母,“ B”是G的亲本等)

A--+
|  D
|  E
|  F
|
B--+
|  G
|
C--+
   H
   I

假设我有一个MasterNodes作为父对象的IEnumerable(A,B,C)和给定的一个父对象X I可以通过X.children得到其孩子的IEnumerable

我知道,我可以用方法的SelectMany或通过枚举所有叶子(子节点)

from parent in Masternodes
from child in parent.children
select child

这会给我这个顺序:

[D,E,F,G,H,I]

,但是这不是我要求的。

什么是LINQ查询来获取在MasterNodes收集的对象的深度优先顺序? (返回第一个父它所有的孩子那么接下来父母那么其所有的孩子等等等)

预期的结果应该是这样一个顺序:

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

更新

我要求的纯.NET准备LINQ。 我知道我可以定义自己的方法做的事情,但我想这仅仅是基于框架提供的方法什么的。

Answer 1:

如果您需要两个以上的层级你可以使用递归去通过你的对象图下面的扩展方法:

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

它变平给定IEnumerable<T>与使用功能的一个映射TIEnumerable<T>描述父-您的数据>子女关系。

深度第一平整由concatinating其子树的每一个元素,然后用加入他们做SelectMany

您可以使用它像这样:

var flattened = Masternodes.Flat(c => c.children);


Answer 2:

如果你有一个像下面一类

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

你的LINQ会

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

测试代码:

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


Answer 3:

因为你只有两个层次,下面的方法应该工作:

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

首先,它创建父加上其子女可枚举:

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

然后将其压平他们SelectMany



Answer 4:

比方说,我们有以下类别:

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

public class ChildNode
{
    public string Value;
}

然后

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


文章来源: Depth-first flattened collection of an object hierarchy using LINQ