So I've been bashing my head against a wall for a while on this one. What Im attempting to do is follow through a category trace defined as "category>child category> child of child category..." but for some reason, of which I am clearly failing to grasp, The categories that should have a parent sometimes fail to set their ParentId, not all the time though!?
string catString = "Category1Name>Category2Name>Category3Name";
if (!string.IsNullOrEmpty(catString)) {
string[] catStrings = catString.Split('>');
ProductCategory[] categories = new ProductCategory[catStrings.Length];
for (int j = 0; j < catStrings.Length; j++) {
string categoryName = catStrings[j];
ProductCategory parent = j > 0 ? categories[j - 1] : null;
if (j > 0) {
categories[j] = _context.ProductCategories.SingleOrDefault(x => x.Name.ToUpper().Replace(" ", "") == categoryName.ToUpper().Replace(" ", "") && x.ParentId == parent.Id);
} else {
categories[j] = _context.ProductCategories.SingleOrDefault(x => x.Name.ToUpper().Replace(" ", "") == categoryName.ToUpper().Replace(" ", ""));
}
if (categories[j] == null) {
if (j > 0) {
categories[j] = new ProductCategory { Name = categoryName, ParentId = parent.Id };
if (parent.Children == null) {
parent.Children = new List<ProductCategory>();
}
parent.Children.Add(categories[j]);
} else {
categories[j] = new ProductCategory { Name = categoryName };
}
_context.ProductCategories.Add(categories[j]);
categoriesCreated++;
}
}
product.Category = categories.Last();
}
A Category is defined as such
public int Id { get; set; }
public string Name { get; set; }
public int ParentId { get; set; }
public virtual List<ProductCategory> Children { get; set; }
String Examples
Glassware>Shot Glasses
Glassware>Wine Glasses
Glassware>Glass Carafes/Decanters/Jugs>Glass Carafes
Glassware>Glass Carafes/Decanters/Jugs>Glass Jugs
Tableware>Cutlery>Premium 18/10
Something simple like this works, using a TreeNode object to contain everything.
public class SO50846156
{
public TreeNode Test(String[] data)
{
var root = new TreeNode();
foreach (var line in data)
{
var split = line.Split('>');
var count = split.Length;
var item = root.Nodes.Add(split[0]);
if (1 < count)
{
var subCat = item.Nodes.Add(split[1]);
if (2 < count)
{
var catName = subCat.Nodes.Add(split[2]);
}
}
}
return root;
}
}
The root element gets created every time, and you get a node for each line of your data.
I'm not sure what yours is trying to accomplish that is different, but maybe this gives you some ideas.
Related
I need your help in getting parent-child URL list from full URL, maybe using recursively.
For example, below is URL in flat structure. I have to parse in parent-child form with inner level of child structure.
https://domain/UrlA/UrlA_L1/UrlA_L1_L2
https://domain/UrlA/UrlA_L1/UrlA2_L1_L2
https://domain/UrlB/UrlB_L1/UrlB_L1_L2
https://domain/UrlC/UrlC_L1/UrlC_L1_L2
https://domain/UrlD/UrlD_L1/UrlD_L1_L2/UrlD_L1_L2_L3
https://domain/UrlE/UrlE_L1/UrlE_L1_L2/UrlE_L1_L2_L3
https://domain/UrlF/UrlF_L1/UrlF_L1_L2/UrlF_L1_L2_L3
into a list of URL with child-parent relationship.
public class HtmlSiteMap
{
public string Url { get; set; }
public string PageTitle { get; set; }
public int UrlLevel { get; set; }
public List<HtmlSiteMap> Childrens { get; set; }
}
my expected output
{
Url: https://domain/UrlA,
PageTitle : UrlA,
UrlLevel : 0 ,
Childrens : {
Url : https://domain/UrlA/UrlA_L1,
PageTitle : UrlA_L1,
UrlLevel : 1,
Childrens : {
Url : https://domain/UrlA/UrlA_L1/UrlA_L1_L2,
PageTitle : UrlA_L1_L2,
UrlLevel : 2,
Childrens : null
},
{
Url : https://domain/UrlA/UrlA_L1/UrlA2_L1_L2,
PageTitle : UrlA2_L1_L2,
UrlLevel : 2,
Childrens : null
}
},
Url: https://domain/UrlB,
PageTitle : UrlB,
UrlLevel : 0 ,
Childrens : {
Url : https://domain/UrlB/UrlB_L1,
PageTitle : UrlB_L1,
UrlLevel : 1,
Childrens : {
Url : https://domain/UrlB/UrlB_L1/UrlB_L1_L2,
PageTitle : UrlB_L1_L2,
UrlLevel : 2,
Childrens : null
}
}
.................
.................
..................
}
I have tried to achieve by splitting and recursively. But unable to get a result. Your help will be appreciated.
Here is another reverse solution. I am working on preordered list, constructing nodes from roots to leaves. This code looks more readable and understandable by beginners in recursion.
static void Main(string[] args)
{
var input = new[]
{
new Uri("https://domain/UrlA/UrlA_L1/UrlA_L1_L2"),
new Uri("https://domain/UrlA/UrlA_L1/UrlA2_L1_L2"),
new Uri("https://domain/UrlB/UrlB_L1/UrlB_L1_L2"),
new Uri("https://domain/UrlC/UrlC_L1/UrlC_L1_L2"),
new Uri("https://domain/UrlD/UrlD_L1/UrlD_L1_L2/UrlD_L1_L2_L3"),
new Uri("https://domain/UrlE/UrlE_L1/UrlE_L1_L2/UrlE_L1_L2_L3"),
new Uri("https://domain/UrlF/UrlF_L1/UrlF_L1_L2/UrlF_L1_L2_L3")
};
var rows = input.Select(u => u.AbsolutePath.Substring(1))
.OrderBy(s => s).Select(s => s.Split('/')).ToList();
var rootNodes = new List<HtmlSiteMap>();
ProcessNodes(rootNodes, rows,
input.Select(u => $"{u.Scheme}://{u.Host}/").Distinct().FirstOrDefault(), 0);
foreach (var node in rootNodes)
Console.WriteLine(node.ToString());
}
static void ProcessNodes(List<HtmlSiteMap> children, List<string[]> rows, string prefix, int level)
{
if (rows.Count == 0)
return;
HtmlSiteMap currentNode = null;
var subRows = new List<string[]>();
foreach (var parts in rows)
{
if (parts.Length == 0)
continue;
subRows.Add(parts.Skip(1).ToArray());
if (currentNode != null && currentNode.PageTitle == parts[0])
continue;
if(currentNode != null)
ProcessNodes(currentNode.Children, subRows, prefix + currentNode.PageTitle + "/", level + 1);
currentNode = new HtmlSiteMap
{
Url = prefix + parts[0],
PageTitle = parts[0],
UrlLevel = level
};
children.Add(currentNode);
subRows.Clear();
}
if(currentNode != null && subRows.Count > 0)
ProcessNodes(currentNode.Children, subRows, prefix + currentNode.PageTitle + "/", level + 1);
}
public class HtmlSiteMap
{
public string Url { get; set; }
public string PageTitle { get; set; }
public int UrlLevel { get; set; }
//Also renamed this from Childrens to Children
public List<HtmlSiteMap> Children { get; set; }
public HtmlSiteMap()
{
Children = new List<HtmlSiteMap>();
}
//Borrowed this from previous answer
public override string ToString()
{
var shift = new string(' ', UrlLevel);
var sb = new StringBuilder();
sb.AppendLine(shift + $"Url: {Url},");
sb.AppendLine(shift + $"PageTitle: {PageTitle},");
sb.AppendLine(shift + $"UrlLevel: {UrlLevel},");
sb.AppendLine(shift + "Children:");
if (Children.Count == 0)
{
sb.AppendLine(shift + "-");
}
else
{
foreach (var child in Children)
{
sb.AppendLine(child.ToString());
}
}
return sb.ToString();
}
}
A base version (without errors handling) may look like this:
static void Main(string[] args)
{
var input = new List<string>
{
"https://domain/UrlA/",
"https://domain/UrlA/UrlA_L1/",
"https://domain/UrlA/UrlA_L1/UrlA_L1_L2",
"https://domain/UrlA/UrlA_L1/UrlA2_L1_L2",
"https://domain/UrlB",
"https://domain/UrlB/UrlB_L1",
"https://domain/UrlB/UrlB_L1/UrlB_L1_L2",
"https://domain/UrlC/UrlC_L1/UrlC_L1_L2",
"https://domain/UrlD/UrlD_L1/UrlD_L1_L2/UrlD_L1_L2_L3",
"https://domain/UrlE/UrlE_L1/UrlE_L1_L2/UrlE_L1_L2_L3",
"https://domain/UrlF/UrlF_L1/UrlF_L1_L2/UrlF_L1_L2_L3"
};
var output = new List<HtmlSiteMap>();
foreach (var url in input)
{
var parts = url.Split(#"/", StringSplitOptions.RemoveEmptyEntries);
var current = new HtmlSiteMap
{
Url = url,
PageTitle = parts[^1]
};
var parentName = parts[^2];
static HtmlSiteMap FindParent(List<HtmlSiteMap> score, string name)
{
foreach (var item in score)
{
if (item.PageTitle == name)
{
return item;
}
var inChild = FindParent(item.Childrens, name);
if (inChild != null)
{
return inChild;
}
}
return null;
}
var parent = FindParent(output, parentName);
if (parent == null)
{
current.UrlLevel = 1;
output.Add(current);
}
else
{
current.UrlLevel = parent.UrlLevel + 1;
parent.Childrens.Add(current);
}
}
foreach (var current in output)
{
Console.WriteLine(current.ToString());
}
Console.ReadLine();
}
public class HtmlSiteMap
{
public string Url { get; set; }
public string PageTitle { get; set; }
public int UrlLevel { get; set; }
public List<HtmlSiteMap> Children { get; set; }
public HtmlSiteMap()
{
Children = new List<HtmlSiteMap>();
}
public override string ToString()
{
var shift = new string(' ', UrlLevel);
var sb = new StringBuilder();
sb.AppendLine(shift + $"Url: {Url},");
sb.AppendLine(shift + $"PageTitle: {PageTitle},");
sb.AppendLine(shift + $"UrlLevel: {UrlLevel},");
sb.AppendLine(shift + "Children:");
if (Children.Count == 0)
{
sb.AppendLine(shift + "-");
}
else
{
foreach (var child in Children)
{
sb.AppendLine(child.ToString());
}
}
return sb.ToString();
}
}
I have a set of data that have duplication because of joining to another table. I need to remove the duplicate and add to another List and each of that element include a list of some element.
As example :
I need to insert this data to the list: List<ExistingQuestionDTO> existingQuestions = new List<ExistingQuestionDTO>();
public class ExistingQuestionDTO
{
public int Id { get; set; }
public int QuestionId { get; set; }
public string QuestionTitle { get; set; }
public string SurveyTitle { get; set; }
public int SurveyId { get; set; }
public string OptionType { get; set; }
public IEnumerable<Tag> Tags { get; set; }
}
I took this data to below List:IEnumerable<ExistingQuestionSpResult> existingQuestionSpResults
and try to make an list using below algorithm. But it wont give an expected result.
private IEnumerable<ExistingQuestionDTO> MakeExistingQuestionSearchableDTO(
IEnumerable<ExistingQuestionSpResult> existingQuestionSpResults)
{
int previousQuestionId = 0;
List<Tag> exitingTags = new List<Tag>();
List<Tag> newTags = new List<Tag>();
List<ExistingQuestionDTO> existingQuestions = new List<ExistingQuestionDTO>();
ExistingQuestionDTO previousExistingQuestionDTO = new ExistingQuestionDTO();
foreach (var questionSpResult in existingQuestionSpResults)
{
if (questionSpResult.QuestionId == previousQuestionId ||
previousQuestionId == 0)
{
//Adding new tag if questionId exist for existing tag
if (!(newTags.Count == 0))
{
exitingTags.AddRange(newTags);
//Clear newTags array here...
newTags.Clear();
}
//Add Tags for same array.
if (!(questionSpResult.ColumnName == "NULL"))
{
Tag tag = new Tag
{
TagId = (Guid)questionSpResult.TagId,
TagName = questionSpResult.ColumnName
};
exitingTags.Add(tag);
}
}
else
{
//Add Tags for new array with Other Items too...
exitingTags.Clear();
newTags.Clear();
if (!(questionSpResult.ColumnName == "NULL"))
{
Tag tag = new Tag
{
TagId = (Guid)questionSpResult.TagId,
TagName = questionSpResult.ColumnName
};
newTags.Add(tag);
}
}
ExistingQuestionDTO existingQuestionDTO = new ExistingQuestionDTO
{
Id = questionSpResult.Id,
QuestionId = questionSpResult.QuestionId,
QuestionTitle = questionSpResult.QuestionTitle,
SurveyId = questionSpResult.SurveyId,
SurveyTitle = questionSpResult.SurveyTitle,
OptionType = questionSpResult.OptionType,
Tags = exitingTags.Count != 0 ? exitingTags : newTags
};
if (questionSpResult.QuestionId == previousQuestionId)
{
//Update Tag in relevant node...
//existingQuestions.RemoveAt((int)questionSpResult.QuestionId - 1);
//existingQuestions.Remove(previousExistingQuestionDTO);
//existingQuestions.Add(existingQuestionDTO);
//existingQuestions.Insert(((int)questionSpResult.QuestionId - 1),
// existingQuestionDTO);
var foundQuestion = existingQuestions.Find(a =>
a.QuestionId == questionSpResult.QuestionId);
foundQuestion.Tags = exitingTags;
existingQuestions[(int)questionSpResult.QuestionId - 1] = foundQuestion;
}
else
{
existingQuestions.Add(existingQuestionDTO);
}
previousQuestionId = questionSpResult.QuestionId;
previousExistingQuestionDTO = existingQuestionDTO;
}
IEnumerable<ExistingQuestionDTO> exitingQuestionList = existingQuestions;
return exitingQuestionList;
}
Can somebody show me what went wrong here ?
QuestionId 3 should have Tags.count => 2. But for here it gives 17. I am so confused.
Since redundancy reason is not mentioned properly and row-wise its completely unique except for questionid 3 where the status has both critical and important. So, first, you have to add a filter for the same and see if you are getting completely unique results or not.
I have a list of Orders that contains subOrders and so on. These are linked via the ChildOrderID and OrderID. However, within each order there are Products and child products that are linked via the PID and ParentPID. Not every product however has a child product.
I have attached an example screenshot of the data in the db to illustrate what I mean and what I hope to achieve. The issue I'm having is that I need to take this flat file structure and put it into a nested c# list. Each BOMLineClass has a list of BOMLinesClass
var navigationItems = bomline.Select(
i => new BOMLineClass
{
ParentOrderID = i.ParentOrderID,
BSOOrderNo = i.BSOOrderNo,
BSODemandDate = i.BSODemandDate,
OrderTypeDesc = i.OrderTypeDesc,
OrderType = i.OrderType,
BuildRef = i.BuildRef,
HasSubAssembly = i.HasSubAssembly,
ChildOrderID= i.ChildOrderID,
ChildOrderNo= i.ChildOrderNo,
OrderID = i.OrderID,
OrderLineID = i.OrderLineID,
ProductCode = i.ProductCode,
ParentPID = i.ParentPID,
PID = i.PID,
}
).ToList();
foreach (var i in navigationItems)
{
i.BOMLines = navigationItems.Where(n => n.ChildOrderID== i.OrderID).ToList();
foreach (var x in i.BOMLines)
{
//Thought I could link the children via the product ID and parent product Id here
}
}
List<BOMLineClass> rootNavigationItems2 = navigationItems.Where(n => n.ChildOrderID == false).ToList();
bh.BOMLines = rootNavigationItems2;
I've been struggling with this for at least 5 days now.
See if following works. You have to start at leafs where ChildOrderID is null and work your way up to root. You also need to have siblings and children nodes. See code below
using System;
using System.Collections.Generic;
using System.Collections;
using System.Linq;
using System.Text;
using System.Data;
namespace ConsoleApplication1
{
class Program
{
static DataTable dt = new DataTable();
static void Main(string[] args)
{
dt.Columns.Add("ChildOrderID", typeof(int));
dt.Columns.Add("ChildOrderNo", typeof(string));
dt.Columns.Add("OrderID", typeof(int));
dt.Columns.Add("OrderLineID", typeof(int));
dt.Columns.Add("ProductCode", typeof(string));
dt.Columns.Add("PID", typeof(int));
dt.Columns.Add("ParentPID", typeof(int));
dt.Rows.Add(null, null, 40551, 193085, "BP6FS", 261649, 303032);
dt.Rows.Add(null, null, 40551, 193086, "HT1-BP", 299119, 303032);
dt.Rows.Add(40551, "BSOMSO20022DDT_1_2", 40550, 193083, "AG947", 253420, 290961);
dt.Rows.Add(40551, "BSOMSO20022DDT_1_2", 40550, 193084, "JS10", 303032, 290961);
dt.Rows.Add(40550, "BSOMSO20022DDT_1", 40549, 193081, "CA9680", 266226, 269143);
dt.Rows.Add(40550, "BSOMSO20022DDT_1", 40549, 193082, "FU552-BP", 290961, 3269143);
List<BOMLineClass> navigationItems = BOMLineClass.GroupBOM(dt);
foreach (BOMLineClass order in navigationItems)
{
BOMLineClass.Print(order, 0);
}
Console.ReadLine();
}
}
public class BOMLineClass
{
public int ParentOrderID { get;set;}
public string BSOOrderNo { get;set;}
public DateTime BSODemandDate { get;set;}
public string OrderTypeDesc { get;set;}
public string OrderType { get;set;}
public string BuildRef { get;set;}
public string HasSubAssembly { get;set;}
public int? ChildOrderID { get;set;}
public string ChildOrderNo { get;set;}
public int OrderID { get;set;}
public int OrderLineID { get;set;}
public string ProductCode { get;set;}
public int ParentPID { get;set;}
public int PID { get; set; }
public List<BOMLineClass> children { get; set; }
public List<BOMLineClass> siblings { get; set; }
static DataTable dt;
public static List<BOMLineClass> GroupBOM(DataTable dt)
{
BOMLineClass.dt = dt;
List<BOMLineClass> leafOrders = new List<BOMLineClass>();
foreach(DataRow row in dt.AsEnumerable().Where(x => x.Field<int?>("ChildOrderID") == null))
{
leafOrders.Add(AddFields(row));
}
return GroupBOMRecursive(leafOrders);
}
static List<BOMLineClass> GroupBOMRecursive(List<BOMLineClass> childOrders)
{
List<BOMLineClass> orders = new List<BOMLineClass>();
var groups = childOrders.GroupBy(x => x.OrderID).ToList();
Boolean hasParents = false;
foreach (var group in groups)
{
//find parent datarow
List<DataRow> parentRow = dt.AsEnumerable().Where(x => x.Field<int?>("ChildOrderID") == group.Key).ToList();
if (parentRow.Count == 0)
{
//no parent
orders.Add(group.First());
}
else
{
hasParents = true;
BOMLineClass order = null;
for (int i = 0; i < parentRow.Count; i++)
{
if (i == 0)
{
order = AddFields(parentRow[i]);
order.children = new List<BOMLineClass>();
order.children.AddRange(group);
orders.Add(order);
}
else
{
if (order.siblings == null) order.siblings = new List<BOMLineClass>();
order.siblings.Add(AddFields(parentRow[i]));
}
}
}
}
if (hasParents)
{
return GroupBOMRecursive(orders);
}
else
{
return orders;
}
}
static public BOMLineClass AddFields(DataRow row)
{
BOMLineClass order = new BOMLineClass();
order.ChildOrderID = row.Field<int?>("ChildOrderID");
order.ChildOrderNo = row.Field<string>("ChildOrderNo");
order.OrderID = row.Field<int>("OrderID");
order.OrderLineID = row.Field<int>("OrderLineID");
order.ProductCode = row.Field<string>("ProductCode");
order.PID = row.Field<int>("PID");
order.ParentPID = row.Field<int>("ParentPID");
return order;
}
public static void Print(BOMLineClass order, int level)
{
const int IDENT = 10;
Console.WriteLine("{0}{1}({2})", new string('-', IDENT * level), order.OrderID, order.ParentPID);
if (order.siblings != null)
{
foreach (BOMLineClass sibling in order.siblings)
{
Console.WriteLine("{0}{1}({2})", new string('-', IDENT * level), sibling.OrderID, sibling.ParentPID);
}
}
if (order.children != null)
{
foreach (BOMLineClass child in order.children)
{
Print(child, level + 1);
}
}
}
}
}
i want to write a C# function which returns "alamaba" when i pass "Montgomery".
2nd example: Sitka --> Alaska
here is the list of the example:
List<PopulationUSA> result = new List<PopulationUSA>();
PopulationUSA usa = new PopulationUSA("Population in USA", 316128839, new List<PopulationUSA>());
result.Add(usa);
PopulationUSA alabama = new PopulationUSA("Alabama", 4833722, new List<PopulationUSA>());
usa.Items.Add(alabama);
alabama.Items.Add(new PopulationUSA("Birmingham", 212113, null));
alabama.Items.Add(new PopulationUSA("Montgomery", 201332, null));
alabama.Items.Add(new PopulationUSA("Mobile", 194899, null));
PopulationUSA alaska = new PopulationUSA("Alaska", 735132, new List<PopulationUSA>());
usa.Items.Add(alaska);
alaska.Items.Add(new PopulationUSA("Juneau", 32660, null));
alaska.Items.Add(new PopulationUSA("Ketchikan", 8214, null));
alaska.Items.Add(new PopulationUSA("Sitka", 9020, null));
here is the class:
public class PopulationUSA
{
public PopulationUSA(string name, int value, List<PopulationUSA> items)
{
Name = name;
Value = value;
Items = items;
}
public string Name { get; set; }
public int Value { get; set; }
public List<PopulationUSA> Items { get; set; }
}
How can i do that?
Thanks
you can add this method to the PopulationUSA class
public string FindParentsOfGrandChildren(string _name)
{
List<PopulationUSA> parents = Items.Where(s => s.Items.Any(c => c.Name == _name)).ToList();
if (parents != null)
{
string listparents = string.Empty;
for (int i = 0; i < parents.Count; i++)
{
if (i == 0)
{
listparents += parents[i].Name;
}
else
{
listparents += ", " + parents[i].Name;
}
}
return listparents;
}
else
{
return "Not found";
}
}
then use it like this in your example:
string WhereDoIBelong = usa.FindParentsOfGrandChildren("Montgomery")
it would be much better as a recursive method, finding parents of any type (not just "grandchildren") but that is your work!
I have this object:
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; }
}
I want to calculate using a lambda expression, the depth of the object, how many layers of the object in itself exists?
I saw this JavaScript post, but I am struggling to translate it to a one line lambda statement.
Lets say the object is as this new dtHeader(){ ParentHeader = null, HeaderText = "col1" };
the result would be 1
and for new dtHeader(){ ParentHeader = new dtHeader(){ ParentHeader = null, HeaderText = "col1" }, HeaderText = "col1" }; the result would be 2
I want to achieve this with a list<dtHeader>, so some of them would have a depth of 1 and others with deeper depths, and want the deepest depth.
_______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_|___|
It must go infinitly(Until where it allows for objects to heap up inside eachother) deep.
var HeaderLayerCount = lDtCol.Where(n => n.ParentHeader != null)
.Where(n => n.ParentHeader.ParentHeader != null)
.Where(n => n.ParentHeader.ParentHeader.ParentHeader != null);
EDIT:
I just want to add that if you want to work on a specific depth level, for instance, all objects on a depth of 3, you can use this extra recursion function in the class
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);
}
}
You can use it like so:
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
}
Why not implementing a int GetDepth() method on your class, that will reach the top most ancestor, counting each level?
Your query would then be much simpler.
I was outrunned by Frode, kudos to him
I had the same implementation:
public int GetDepth()
{
if (ParentHeader == null)
{
return 1;
}
else return 1 + ParentHeader.GetDepth();
}
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);
}
}
}
Here's a lambda expression to get what you want:
Func<dtHeader, int> getDepth = null;
getDepth = dth =>
{
var depth = 1;
if (dth.ParentHeader != null)
{
depth += getDepth(dth.ParentHeader);
}
return depth;
};
You have to define it in two parts (assigning null & assigning the body) to let recursion work.
I modified Enigmativity's answer to make it work correctly:
Func<dtHeader, int, int> getDepth = null;
getDepth = (dth, depth) =>
{
if (dth.ParentHeader != null)
{
depth = getDepth(dth.ParentHeader, ++depth);
}
return depth;
};
Call it like this:
int depth = getDepth(header, 0)