尝试获取所有不为空的List<Node>()
的列表。子节点该怎么做?
public class Node
{
public string Name { get; set; }
public List<Node> Nodes { get; set; }
}
public class Program
{
static void Main(string[] args)
{
List<Node> Items = new List<Node>();
Items.Add(new Node { Name = "Test0" });
Items.Add(new Node { Name = "Test1" });
Items.Add(new Node { Name = "Test2" });
Items.Add(new Node { Name = "Test3" });
Items.Add(new Node { Name = "Test4" });
Items.Add(new Node { Name = "Test5" });
Items.Add(new Node
{
Name = "Test6",
Nodes = new List<Node>
{
new Node
{
Name = "Test6.1",
Nodes = new List<Node>
{
new Node
{
Name = "Test6.1.1", Nodes = new List<Node>()
}
}
},
}
});
Items.Add(new Node { Name = "Test7", Nodes = new List<Node> { } });
Items.Add(new Node { Name = "Test8", Nodes = new List<Node> { } });
var NotNullNodes = Items.SelectMany(m => m.Nodes);
}
}
答案 0 :(得分:3)
另一个linq递归解决方案:
public static IEnumerable<Node> GetAllNodes( Node root )
{
if( root == null )
{
yield break;
}
yield return root;
if ( root.Nodes == null )
{
yield break;
}
foreach ( Node descendant in root.Nodes.SelectMany( GetAllNodes ) )
{
yield return descendant;
}
}
像这样使用:
Items.SelectMany( GetAllNodes )
答案 1 :(得分:1)
好吧,SelectMany
仅使一级变平。在您的情况下,您需要对图形进行某种搜索,例如 BFS -宽度优先搜索:
public static partial class EnumerableExtensions {
public static IEnumerable<T> BreadthFirstSearch<T>(
this IEnumerable<T> source,
Func<T, IEnumerable<T>> children) {
if (Object.ReferenceEquals(null, source))
throw new ArgumentNullException(nameof(source));
else if (Object.ReferenceEquals(null, children))
throw new ArgumentNullException(nameof(children));
HashSet<T> proceeded = new HashSet<T>();
Queue<IEnumerable<T>> queue = new Queue<IEnumerable<T>>();
queue.Enqueue(source);
while (queue.Count > 0) {
IEnumerable<T> src = queue.Dequeue();
if (Object.ReferenceEquals(null, src))
continue;
foreach (var item in src)
if (proceeded.Add(item)) {
yield return item;
queue.Enqueue(children(item));
}
}
}
}
然后您可以放
var NotNullNodes = Items.BreadthFirstSearch(item => item.Items ?? new List<Node>());
答案 2 :(得分:0)
这是一个递归获取所有节点的函数:
public static List<Node> GetAllNodes(List<Node> items)
{
List<Node> allNodes = new List<Node>();
foreach(Node n in items)
if (n.Nodes != null && n.Nodes.Count > 0)
allNodes.AddRange(GetAllNodes(n.Nodes));
allNodes.AddRange(items);
return allNodes;
}
答案 3 :(得分:0)
如果为IEnumerable创建扩展方法,则可以像使用现有LINQ方法一样使用它。参见extension methods demystified
static IEnumerable<Node> Flatten(IEnumerable<node> nodesWithSubNodes)
{
// Todo: check nodesWithSubNodes not null
foreach (var node in nodesWithSubNodes)
{
yield return node;
if (node.SubNodes != null) // not needed if you are certain that not null
{
foreach (var subNode in nodes.SubNodes.Flatten())
yield return subNode;
}
}
用法:
var result = myNodes.Flatten()
.Take(3)
.ToList();
对此的好处是,它看起来像现有的LINQ函数。它也是非常有效的,因为它不枚举比实际查询更多的元素,如示例中所示。