Определить целое число иерархии из родительского поля 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 2

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));
}

Конечно, это потребовало бы признания недействительными всех кэширование результатов при необходимости пересчета после изменения структуры иерархии.