Получить глубину дерева объектов одного типа с помощью лямбда-выражения
У меня есть этот объект:
public class dtHeader
{
public dtHeader ParentHeader { get; set; }
public string HeaderText { get; set; }
public string DataField { get; set; }
public bool Visible { get; set; }
public int DisplayOrder { get; set; }
}
Я хочу вычислить, используя лямбда-выражение, глубину объекта, сколько слоев объекта в себе существует?
Я видел Этот пост JavaScript, но я изо всех сил пытаюсь перевести его в однострочный лямбда-оператор.
Предположим, что объект таков new dtHeader(){ ParentHeader = null, HeaderText = "col1" };
результатом будет 1
И для new dtHeader(){ ParentHeader = new dtHeader(){ ParentHeader = null, HeaderText = "col1" }, HeaderText = "col1" };
результатом будет 2
Я хочу достичь этого с помощью list<dtHeader>
, поэтому некоторые из них будут иметь глубину 1 и другие с более глубокими глубинами, и хотят самой глубокой глубины.
_______ITEM_IN_LIST_OBJECT__
______1___2___3___4___5___6_
D 1. |_o_|_o_|_o_|_o_|_o_|_o_|
E 2. |_o_|___|_o_|___|_o_|_o_|
P 3. |___|___|_o_|___|_o_|___|
T 4. |___|___|___|___|_o_|___|
H 5. |___|___|___|___|_o_|___|
Он должен идти бесконечно (до тех пор, пока он не позволит объектам нагромождаться внутри друг друга) глубоко.
var HeaderLayerCount = lDtCol.Where(n => n.ParentHeader != null)
.Where(n => n.ParentHeader.ParentHeader != null)
.Where(n => n.ParentHeader.ParentHeader.ParentHeader != null);
редактировать: Я просто хочу добавить, что если вы хотите работать на определенном уровне глубины, например, все объекты на глубине 3, Вы можете использовать эту дополнительную рекурсивную функцию в классе
public class dtCol
{
public dtCol ParentHeader { get; set; }
public string HeaderText { get; set; }
public string DataField { get; set; }
public bool Visible { get; set; }
public int DisplayOrder { get; set; }
public int Depth { get { return ParentHeader != null ? ParentHeader.Depth + 1 : 1; } }
public int CurrentDepth { get; set; } //Set on initialisation
public dtCol getParent(dtCol col, int getDepth) //Gets the parent on a specific level after the first base level (1) else returns the previous not null child
{
return (col.ParentHeader != null && col.ParentHeader.CurrentDepth == getDepth) ? col.ParentHeader : this.getParent(col.ParentHeader, getDepth);
}
}
Вы можете использовать его следующим образом:
var HeaderLayerCount = lDtCol.OrderByDescending(n => n.Depth).First().Depth;
for (int hlc = 1; hlc <= HeaderLayerCount; hlc++)
{
var headerrow = new List<dtCol>();
//This foreach adds the parent header if not null else adds the not null child
lDtCol.ForEach(n =>
{
var h = n.getParent(n, hlc); //Get Parent, null is returned if parent does not exists
headerrow.Add((h != null) ? h : n); //If parent is null, add base dtCol so that the headers can be merged upwards.
});
//Do what you need with your new single dimensional list of objects
}
4 ответа:
using System; using System.Linq; namespace ConsoleApplication3 { public class dtHeader { public dtHeader ParentHeader { get; set; } public string HeaderText { get; set; } public string DataField { get; set; } public bool Visible { get; set; } public int DisplayOrder { get; set; } public int Depth { get { // If header has parent, then this depth is parent.depth + 1 if (ParentHeader != null) return ParentHeader.Depth+1; else return 1; // No parent, root is depth 1 } } } class Program { static void Main(string[] args) { dtHeader[] headers = { new dtHeader { HeaderText = "dt1" }, new dtHeader { HeaderText = "dt2" }, new dtHeader { HeaderText = "dt3" }, new dtHeader { HeaderText = "dt4" }, new dtHeader { HeaderText = "dt5" } }; headers[1].ParentHeader = headers[0]; headers[2].ParentHeader = headers[1]; headers[3].ParentHeader = headers[2]; headers[4].ParentHeader = headers[3]; var deepest = headers.OrderByDescending(item=>item.Depth).First(); Console.WriteLine(deepest.Depth+ ", " + deepest.HeaderText); var runner = deepest; while (runner.ParentHeader != null) runner = runner.ParentHeader; Console.WriteLine("The deepest root header is:" + runner.HeaderText); } } }
Почему бы не реализовать метод int GetDepth () в вашем классе, который достигнет самого верхнего предка, считая каждый уровень?
Тогда ваш запрос будет намного проще.
Меня обогнал Фроде, слава ему
У меня была такая же реализация:
public int GetDepth() { if (ParentHeader == null) { return 1; } else return 1 + ParentHeader.GetDepth(); }
Вот лямбда-выражение, чтобы получить то, что вы хотите:
Func<dtHeader, int> getDepth = null; getDepth = dth => { var depth = 1; if (dth.ParentHeader != null) { depth += getDepth(dth.ParentHeader); } return depth; };
Вы должны определить его в двух частях (назначение
null
и назначение тела), чтобы позволить рекурсии работать.