我的课程如下:
public class SiloNode
{
public string Key { get; private set; }
public string ParentKey { get; private set; }
public string Text { get; private set; }
public string Url { get; private set; }
}
所有节点都包含在列表中:
List<SiloNode> nodes = new List<SiloNode>();
如您所见,该类包含ParentKey属性,因此可以找到该项的父项,祖父母等,直到列表顶部被选中为止。
目前,我需要遍历2个级别,从下面的代码中您可以看到,它看起来已经很笨重了。现在,我需要修改代码以遍历3个级别,而且我担心它会变得混乱。
有没有更清洁的方法来实现我想要的?
string GetStartGroup(string currentUrl)
{
string startGroup = null;
var currentNode = Silos.Silo.SingleOrDefault(x => x.Url == currentUrl);
if (currentNode != null)
{
var parentNode = Silos.Silo.SingleOrDefault(x => x.Key == currentNode.ParentKey);
if (parentNode != null) startGroup = parentNode.ParentKey;
}
return startGroup;
}
答案 0 :(得分:1)
重复使用列表上的SingleOrDefault
会使算法变慢:为n个节点找到父节点需要O(n 2 )时间。
您应该先创建一个Dictionary<string,SiloNode>
,然后遍历字典中的层次结构:
var lookup= nodes.ToDictionary(n => n.Key);
...
SiloNode FindParent(SiloNode node, int levelsUp, IDictionary<string,SiloNode> lookup) {
while (node != null && levelsUp != 0) {
if (node.ParentKey == null || !lookup.TryGetValue(node.ParentKey, out var parent)) {
return node;
}
node = parent;
levelsUp--;
}
return node;
}
这将查找最高levelsUp
级的父级。如果您正在寻找最后一个可能的父代,请按如下所示修改代码:
SiloNode FindParent(SiloNode node, IDictionary<string,SiloNode> lookup) {
while (true) {
if (node?.ParentKey == null || !lookup.TryGetValue(node.ParentKey, out var parent)) {
return node;
}
node = parent;
}
}
或递归
SiloNode FindParent(SiloNode node, IDictionary<string,SiloNode> lookup) {
return node?.ParentKey != null && lookup.TryGetValue(node.ParentKey, out var parent)
? FindParent(parent, lookup)
: node;
}
答案 1 :(得分:1)
您可以通过递归来做到这一点。
string GetStartGroup(string currentUrl)
{
var node = nodes.Single(x => x.Url == currentUrl);
if (node.ParentKey == null)
return node.Key;
return GetStartGroup(nodes.Single(x => x.Key == node.ParentKey).Url);
}
或者:
string GetStartGroup(string currentUrl)
{
return GetStartNode(nodes.Single(x => x.Url == currentUrl)).Key;
}
SiloNode GetStartNode(SiloNode node)
{
if (node.ParentKey == null)
return node;
return GetStartNode(nodes.Single(x => x.Key == node.ParentKey));
}
答案 2 :(得分:0)
您可以更改
if (parentNode != null) startGroup = parentNode.ParentKey;
到
if (parentNode != null) startGroup = GetStartGroup(currentNode.parentUrl /*or something similar*/);
但是,最好使用迭代循环。我不太了解您的问题,无法给您提示,但是伪代码看起来像这样:
while (parentNode != null) {
currentNode = currentNode.parentNode;
parentNode = currentNode.parentNode;
}
您可能需要致电SingleOrDefault
,但如果您有直接参考,则应改用该参考。
答案 3 :(得分:0)
只需将其放入方法中即可
public static Silo Up(Silo current, IEnumerable<Silo> collection)
{
return collection.FirstOrDefault((it) => it.ParentKey == it.Key);
}
或作为扩展方法:
public static SiloExtensions
{
public static Silo Up(this Silo current, IEnumerable<Silo> collection)
{
return collection.FirstOrDefault((it) => it.ParentKey == it.Key);
}
}
因此您只需silo.Up()?.Up()
请注意,这相当慢。 根据实际操作,您可能希望将实际的父对象引入字段或提供对其访问的包装对象。
这样的包装对象可能看起来像这样:
public class SiloWrapper
{
public Silo Wrapped { get; }
public Silo Parent { get; }
private SiloWrapper(Silo silo, Silo parent)
{
this.Wrapped = silo;
this.Parent = parent;
}
public IEnumerable<SiloWrapper> Map(IEnumerable<Silo> silos)
{
var dict = silos.ToDictionary((s) => s.Key);
foreach(var s in silos)
{
yield return new SiloWrapped(s, s.ParentKey == null ? null : dict[s.ParentKey]);
}
}
}
然后上下移动,只需要调用SiloWrapped.Map(<methodToGetSiloCollection>)
并准备好所有包装的筒仓即可使用。
如果可能需要考虑GarbageCollection,则也可以改用WeakReference<Silo> ParentWeak