Определить целое число иерархии из родительского поля C#
Мне нужно определить уровень иерархии для отображения дерева, мне не нужно связывать отношения в данный момент, у меня есть список объектов следующим образом:
public class ObjectData
{
public string ID;
public string hierarchyParent;
public int hierarchyLevel;
}
Мне нужно установить целое число уровня иерархии на основе его уровня строки. Var hierarchyParent содержит идентификатор своего родителя. Я не знаю, какой ширины будет каждый столбец и сколько строк, поэтому он должен быть динамическим с целым числом уровня иерархии либо по возрастанию, либо по убыванию. До сих пор мне удавалось определить верхний ряд но я не уверен, как продолжить, любая помощь будет оценена! Пока что:
List<ObjectData> Sort(List<ObjectData> objectToBeSorted){
List<ObjectData> returnlist = new List<ObjectData>();
string topObject = null;
foreach(ObjectData obj in objectToBeSorted)
{
if(obj.hierarchyParent == null){
topObject = obj.ID;
obj.hierarchyLevel = 1;
}
}
foreach(ObjectData obj in objectToBeSorted)
{
if(obj.hierarchyParent == topObject){
}
}
return returnlist;
}
2 ответа:
Вот быстрая попытка с образцами данных и рекурсивными вызовами:
Полезная часть находится в методе AssignChild.
public class ObjectData { public string ID; public string hierarchyParent; public int hierarchyLevel; } void Main() { var objects = new List<ObjectData>() { new ObjectData() { ID = "Obj12", hierarchyParent = null }, new ObjectData() { ID = "Obj5", hierarchyParent = "Obj12" }, new ObjectData() { ID = "Obj9", hierarchyParent = "Obj12" }, new ObjectData() { ID = "Obj7", hierarchyParent = "Obj5" }, new ObjectData() { ID = "Obj99", hierarchyParent = "Obj58" }, new ObjectData() { ID = "Obj58", hierarchyParent = "Obj5" } }; ObjectData top = objects.Find(p => p.hierarchyParent == null); top.hierarchyLevel = 1; AssignChild(objects, top); objects.Dump(); } void AssignChild(List<ObjectData> all, ObjectData parent) { var child = all.FindAll(o => o.hierarchyParent == parent.ID); child.ForEach(c => { c.hierarchyLevel = parent.hierarchyLevel +1; AssignChild(all, c); }); }
Его, вероятно, можно оптимизировать, но он должен работать.
Я предлагаю сделать что-то вроде этого:
public int GetHierarchyLevel(ObjectData obj, IEnumerable<ObjectData> allObjects) { if(obj.hierarchyParent == null) return 1; else return 1 + GetHierarchyLevel(allObjects.First(o=>o.ID == obj.hierarchyParent)); }
Конечно, вы должны интегрировать это в свои классы, чтобы можно было заменить аргументы членами класса. Кроме того, обратите внимание, что может потребоваться проверка некоторых ошибок. Это просто должно дать вам представление об алгоритме.
Для повышения производительности я предлагаю механизм кэширования. Например, инициализация
hierarchyLevel
в-1
и использование следующей модификации:public int GetHierarchyLevel(ObjectData obj, IEnumerable<ObjectData> allObjects) { if (obj.hierarchyLevel != -1) return obj.hierarchyLevel; if(obj.hierarchyParent == null) return 1; else return 1 + GetHierarchyLevel(allObjects.First(o=>o.ID == obj.hierarchyParent)); }
Конечно, это потребовало бы признания недействительными всех кэширование результатов при необходимости пересчета после изменения структуры иерархии.