我有一个类(Node),它有一个SubNodes属性,它是Node类的List
我有一个节点列表(每个节点可能有或没有自己的子节点列表)我需要能够在节点列表/子节点中找到一个节点。
我曾尝试在列表中执行查找,但这只会搜索列表中的Node类而不是SubNodes列表。看着C5库和一些二叉树但找不到合适的东西。有什么建议吗?
班级
public class Node
{
public Guid Id { get; set; }
public DateTime Created { get; set; }
public List<Node> Nodes { get;set;}
}
功能(结果是最终结果)
private void GetRecersive(List<Node> list, ref List<Node> result)
{
foreach (Node item in list)
{
if (item.ParentId.Equals(Guid.Empty))
{
result.Add(item);
}
else
{
result.ForEach(x => x.FindNodes(y => y.Id.Equals(item.ParentId)).FirstOrDefault().Nodes.Add(item));
}
List<Node> nodes = GetNodesByParent(item.Id);
GetRecersive(nodes, ref result);
}
}
答案 0 :(得分:4)
正如empi所说,递归搜索是理想的选择。如果你真的有一棵树,即没有周期,就像这样简单:
public class Node
{
// Properties as before
public Node FindById(Guid id)
{
if (id == Id)
{
return this;
}
foreach (Node node in Nodes)
{
Node found = node.FindById(id);
if (found != null)
{
return found;
}
}
return null; // Not found in this subtree
}
}
否则,您需要保留已经访问过的一组(例如HashSet<Node>
)个节点。周期使各种事情变得讨厌:)
你可以使用LINQ重写foreach
循环:
return Nodes.Select(x => x.FindById(id)).FirstOrDefault();
但是我不确定这个特殊情况下的显式循环是否非常清晰(尽管我是一个巨大的LINQ粉丝)。
答案 1 :(得分:2)
您可以添加代表层次结构的代码并使用LINQ:
public class Node
{
// Properties
public IEnumerable<Node> AllNodes
{
get
{
yield return this;
foreach (var node in Nodes.SelectMany(n => n.AllNodes))
yield return node;
}
}
}
并使用LINQ to Objects:
var matches = nodes.SelectMany(n => n.AllNodes).Where(n => n.Created < DateTime.Today);
答案 2 :(得分:1)
你必须递归搜索(在Nodes列表中搜索,然后在之前Nodes列表中每个节点的Nodes列表中搜索等等)并保留访问节点列表(否则如果有循环则永远不会完成在结构中)。你试过这个吗?
答案 3 :(得分:1)
无论它有多深,我都可以这样做来覆盖节点列表:
Node类:
public class Node
{
public Guid Id { get; set; }
public DateTime Created { get; set; }
public List<Node> Nodes { get; set; }
public Node()
{
this.Nodes = new List<Node>();
}
public List<Node> FindNodes(Func<Node, bool> condition)
{
List<Node> resList = new List<Node>();
if (this.Nodes != null && this.Nodes.Count > 0)
{
this.Nodes.ForEach(x =>
{
resList.AddRange(x.FindNodes(condition));
if (condition(x))
resList.Add(x);
}
);
}
return resList;
}
}
拥有此节点列表,例如:
List<Node> nodeList = new List<Node>()
{
new Node() { Id = Guid.NewGuid(), Created = new DateTime(2009, 01, 10),
Nodes = {
new Node() { Id = Guid.NewGuid(), Created = new DateTime(2009, 01, 11) },
new Node() { Id = Guid.NewGuid(), Created = new DateTime(2009, 01, 12) } } },
new Node() { Id = Guid.NewGuid(), Created = new DateTime(2009, 02, 10),
Nodes = {
new Node() { Id = Guid.NewGuid(), Created = new DateTime(2009, 02, 11),
Nodes = {
new Node() { Id = Guid.NewGuid(), Created = new DateTime(2009, 11, 11) },
new Node() { Id = Guid.NewGuid(), Created = new DateTime(2009, 12, 12),
Nodes = {
new Node() { Id = Guid.NewGuid(), Created = new DateTime(2011, 11, 11) },
new Node() { Id = Guid.NewGuid(), Created = new DateTime(2011, 12, 12) } } } } },
new Node() { Id = Guid.NewGuid(), Created = new DateTime(2009, 02, 12) } } },
new Node() { Id = Guid.NewGuid(), Created = new DateTime(2009, 03, 10),
Nodes = {
new Node() { Id = Guid.NewGuid(), Created = new DateTime(2009, 03, 11) },
new Node() { Id = Guid.NewGuid(), Created = new DateTime(2009, 03, 12) } } },
};
我可以找到我想要的任何子节点:
List<Node> resList = new List<Node>();
nodeList.ForEach(x =>
resList.AddRange(x.FindNodes(y => y.Created.Day == 12)));
你可以按照你想要的任何东西来看待。在上面的示例中,我搜索在任何月份和年份的第12天创建的节点。
答案 4 :(得分:0)
似乎我们都把这一切都搞得一团糟。我向我的一位同事展示了这个问题,他制作了以下完美的作品。
private void BuildUpChildren(List<Node> list)
{
foreach (Node item in list)
{
List<Node> nodes = GetNodesByParent(item.Id);
item.Nodes.AddRange(nodes);
BuildUpChildren(nodes);
}
}