c# - 按父母和孩子以及孩子的父母的顺序列表
问题描述
我正在尝试订购应该看起来像这样的列表
- 家长
- Child1(同时是孩子和父母)
- Child2(Child1 的孩子)
- 孩子3
- Child1(同时是孩子和父母)
在使用包含有关 ID、ParentID 等信息的类时。
我正在尝试使用 LINQ 完成这项工作并尝试了不同的解决方案,但没有人完全工作,我知道递归函数会起作用(但真的不喜欢那样),有人可以帮助我使用 LINQ 吗?
我试过这段代码,但 Child2 没有出现。
List<Person> orderedList = new List<Person>();
persons.ForEach(x => {
if (x.ParentID == 0) {
orderedList.Add(x);
orderedList.AddRange(persons.Where(child => child.ParentID == x.Id));
}
});
对于那些投票“否定”的人来说,记住一开始没有人是编程的神,如果我来到这里,这意味着我在 x 小时内很难解决这个问题。而且,如果您认为我的英语不好,我已经知道了,我生来就不会说一口流利的英语,但愿意提供帮助的人会提供帮助。:)
完整代码
public class Person{
public int Id { get; set; }
public string MenuName { get; set; }
public int? ParentID { get; set; }
public string isHidden { get; set; }
public string LinkURL { get; set; }
}
public static List<Person> AddPersons(){
var persons = new List<Person>();
using (var reader = new StreamReader(@"C:\Users\AceDuk\Desktop\Navigation.csv")){
var line = reader.ReadLine(); //Da se izbegne headerot
while ((line = reader.ReadLine()) != null){
var values = line.Split(';');
if (values[2] == "NULL") {
values[2] = "0";
}
persons.Add(new Person(){
Id = Int32.Parse(values[0]),
MenuName = values[1],
ParentID = Int32.Parse(values[2]),
isHidden = values[3],
LinkURL = values[4]
});
}
}
persons.RemoveAll(x => x.isHidden == "True"); //Izbrisi gi site sto se hidden ne gi pokazuvaj..
//persons = persons.OrderBy(x => x.MenuName).ToList(); //Ordered
persons = persons.OrderBy(x => x.LinkURL).ToList(); //Ordered
return persons;
}
static void Main(string[] args){
List<Person> persons = AddPersons();
List<Person> orderedList = new List<Person>();
persons.ForEach(x => {
if (x.ParentID == 0) {
orderedList.Add(x);
orderedList.AddRange(persons.Where(child => child.ParentID == x.Id));
}
});
foreach (var item in orderedList) {
Console.WriteLine(item.MenuName);
}
}
解决方案
通过扩展链表创建双端队列(deque)数据结构:
public class Deque<T> : LinkedList<T> {
public void Enqueue(T item) => AddLast(item);
public T Dequeue() {
var item = First.Value;
RemoveFirst();
return item;
}
public void EnqueueRange(IEnumerable<T> items) {
foreach (var item in items)
Enqueue(item);
}
public void Push(T item) => AddFirst(item);
public T Pop() => Dequeue();
public void PushRange(IEnumerable<T> items) {
foreach (var item in items)
Push(item);
}
public T Peek() => Last.Value;
}
现在,使用以下方法创建从Id
到子级的映射ToLookup
:
var childrenDictionary = persons.Where(p => p.ParentID != 0).ToLookup(p => p.ParentID);
最后,使用双端队列创建工作列表并添加所有根节点:
var workDeque = new Deque<Person>();
workDeque.EnqueueRange(persons.Where(p => p.ParentID == 0));
现在您可以通过workDeque
,将每个根节点添加到orderedPersons
,然后将节点的子节点推workDeque
送到下一步工作:
var orderedPersons = new List<Person>();
while (workDeque.Count > 0) {
var nextPerson = workDeque.Dequeue();
orderedPersons.Add(nextPerson);
workDeque.PushRange(childrenDictionary[nextPerson.Id]);
}
推荐阅读
- docker - 套接字:协议不支持的地址族
- android - Kotlin 获取所选选项的 ID
- python-3.x - 找不到满足 pywin32>=223 要求的版本(来自 pypiwin32)(来自版本:)
- flutter - 如果 GestureDetector 包含 ScrollablePositionedList,则不会触发 onTap 和 onScaleStart
- flutter - Navigator popUntil 后刷新页面
- gradle - 如何定义 gradle 任务依赖关系 - 输入输出或依赖?
- python - 如何使用 python elasticsearch 库将 XML 批量数据加载到 elasticsearch 中?
- php - 我必须如何在 Elasticsearch 中保存类别过滤器?
- wordpress - 将自定义字段添加到自定义 Woocommerce 电子邮件
- git - Git红色和绿色状态图标在文件夹中消失