我有一个对象层次结构(MasterNode - > ChildNodes),其中主节点和子节点属于同一类型,并且只有两个级别(顶级和子级)像这样('A'是D,E的父级)和F,'B'是G的父,等等)
A--+
| D
| E
| F
|
B--+
| G
|
C--+
H
I
假设我有一个 MasterNodes 作为父对象(A,B,C)的IEnumerable并给出一个父对象 X 我可以得到一个IEnumerable的子对象通过 X.children
我知道我可以使用 SelectMany 方法或使用
枚举所有叶子(子节点)from parent in Masternodes
from child in parent.children
select child
这将给我这个序列:
[D,E,F,G,H,I]
,但这不是我要求的。
什么是获取MasterNodes集合中对象的深度优先序列的LINQ查询?(返回第一个父项,然后返回其所有子项,然后是下一个父项,然后是其所有子项等)
预期结果应该是这样的序列:
[A,D,E,F,B,G,C,H,I]
更新:
我要求纯粹的.NET就绪LINQ。我知道我可以定义自己的方法来做事,但我想要的东西只基于框架提供的方法。
答案 0 :(得分:4)
如果您有类似下面的课程
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);
答案 1 :(得分:4)
如果您需要两个以上的层次结构级别,则可以使用以下扩展方法,该方法以递归方式通过对象图形:
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>
映射到描述父级的T
的函数来展平给定的IEnumerable<T>
- &gt;孩子与你的数据的关系。
深度优先展平是通过将每个元素与其子树结合,然后将其与SelectMany
连接来完成的。
你可以像这样使用它:
var flattened = Masternodes.Flat(c => c.children);
答案 2 :(得分:2)
由于您只有两个级别,因此以下方法应该有效:
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
展平它们。
答案 3 :(得分:0)
说,我们有以下课程:
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);
}