我想基于列表数据生成一些字符串:
提供以下课程:
public class Item
{
public int Id { get; set; }
public string Name { get; set; }
public int ParentId { get; set; }
}
我有以下相关Item
对象的列表:
var list = new List<Item>();
list.Add(new Item { Id = 1, Name = "Parent1", ParentId = 0 });
list.Add(new Item { Id = 2, Name = "Child1", ParentId = 1 });
list.Add(new Item { Id = 3, Name = "Child2", ParentId = 1 });
list.Add(new Item { Id = 4, Name = "GrandChild1", ParentId = 2 });
list.Add(new Item { Id = 5, Name = "GrandChild2", ParentId = 2 });
list.Add(new Item { Id = 6, Name = "GrandChild3", ParentId = 3 });
list.Add(new Item { Id = 7, Name = "GrandChild4", ParentId = 3 });
list.Add(new Item { Id = 8, Name = "Parent2", ParentId = 0 });
list.Add(new Item { Id = 9, Name = "Child1", ParentId = 8 });
list.Add(new Item { Id = 10, Name = "Child2", ParentId = 8 });
list.Add(new Item { Id = 11, Name = "GrandChild1", ParentId = 9 });
list.Add(new Item { Id = 12, Name = "GrandChild2", ParentId = 9 });
list.Add(new Item { Id = 13, Name = "GrandChild3", ParentId = 10 });
list.Add(new Item { Id = 14, Name = "GrandChild4", ParentId = 10 });
现在,我想创建像这样的字符串:
"Parent1:Child1:GrandChild1"
"Parent1:Child1:GrandChild2"
"Parent1:Child2:GrandChild3"
"Parent1:Child2:GrandChild4"
"Parent2:Child1:GrandChild1"
"Parent2:Child1:GrandChild2"
"Parent2:Child2:GrandChild3"
"Parent2:Child2:GrandChild4"
我已经尝试过了:
private IList<Item> GetChild(int id, IList<Item> items)
{
var childs = items
.Where(x => x.ParentId == id || x.Id == id)
.Union(items.Where(x => x.ParentId == id)
.SelectMany(y => GetChild(y.Id, items)));
return childs.ToList();
}
此代码返回parent以及所有子级和子级子级,但是我无法从中获得所需的字符串。
那么我该如何使用LINQ或foreach循环来做到这一点?
答案 0 :(得分:1)
通过一些联接,您可以获得预期的输出。
public void WriteStrings()
{
List<Item> items = GetItems();
IEnumerable<string> resultingStrings = from parent in items.Where(x => x.ParentId == 0)
join child in items on parent.Id equals child.ParentId
join grandChild in items on child.Id equals grandChild.ParentId
select string.Format("{0}:{1}:{2}", parent.Name, child.Name, grandChild.Name);
foreach(var item in resultingStrings)
Console.WriteLine(item);
}
输出
Parent1:Child1:GrandChild1
Parent1:Child1:GrandChild2
Parent1:Child2:GrandChild3
Parent1:Child2:GrandChild4
Parent2:Child1:GrandChild1
Parent2:Child1:GrandChild2
Parent2:Child2:GrandChild3
Parent2:Child2:GrandChild4
答案 1 :(得分:0)
以下代码与递归方法遍历列表并打印所需内容。以list为参数调用Traverse方法。
public void Traverse(List<Item> list)
{
var roots = list.Where(e => e.ParentId == 0).ToList();
foreach (var item in roots)
{
Traverse(list, item);
Console.WriteLine();
}
}
private void Traverse(List<Item> list, Item target, string str = "")
{
str += target.Name;
var children = list.Where(e => e.ParentId == target.Id).ToList();
if (!children.Any())
{
Console.WriteLine(str);
return;
}
str += ":";
foreach (var item in children)
{
Traverse(list, item, str);
}
}
答案 2 :(得分:0)
以下是我在评论中提到的两种方法。首先确定叶子,然后为每个叶子工作回到根,建立字符串:
// Build a dictionary of items
var itemsById = list.ToDictionary(i => i.Id);
// Build a dictionary of child items of each node; 0 = root
var childrenById = list.GroupBy(i => i.ParentId).ToDictionary(g => g.Key);
// Find leaf nodes
var leaves = list.Where(i => !childrenById.ContainsKey(i.Id));
// For each leaf, build up a list of parents up to the root then print
foreach (var leaf in leaves)
{
var queue = new LinkedList<Item>();
var cursor = leaf;
do
{
// NB this will get stuck if there's a cycle in your tree.
// You might want to guard against this!
queue.AddFirst(cursor);
}
while (itemsById.TryGetValue(cursor.ParentId, out cursor));
Console.WriteLine(String.Join(":", queue.Select(i => i.Name)));
}
或者,构建一棵树并通过以下方式递归:
// Build a dictionary of child items of each node; 0 = root
var childrenById = list.GroupBy(i => i.ParentId).ToDictionary(g => g.Key);
// Iterate through tree recursively
var path = new LinkedList<Item>();
var output = new List<String>();
Recurse(0, path, childrenById, output);
和
static void Recurse(int parentId, LinkedList<Item> path,
Dictionary<int, IGrouping<int, Item>> childrenById, List<String> output)
{
if (childrenById.ContainsKey(parentId))
{
foreach (var item in childrenById[parentId])
{
path.AddLast(item);
Recurse(item.Id, path, childrenById, output);
path.RemoveLast();
}
}
else
{
// This is a leaf node
output.Add(String.Join(":", path.Select(i => i.Name)));
}
}
答案 3 :(得分:0)
尝试以下代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication1
{
public class Program
{
public static void Main()
{
Item item = new Item();
item.CreateList();
Item.Recursive(0, new List<string>());
foreach(string descendant in Item.descendants)
{
Console.WriteLine(descendant);
}
Console.ReadLine();
}
}
public class Item
{
public static List<string> descendants = new List<string>();
public static List<Item> items = null;
public int Id { get; set; }
public string Name { get; set; }
public int ParentId { get; set; }
public void CreateList()
{
items = new List<Item>() {
new Item { Id = 1, Name = "Parent1", ParentId = 0 },
new Item { Id = 2, Name = "Child1", ParentId = 1 },
new Item { Id = 3, Name = "Child2", ParentId = 1 },
new Item { Id = 4, Name = "GrandChild1", ParentId = 2 },
new Item { Id = 5, Name = "GrandChild2", ParentId = 2 },
new Item { Id = 6, Name = "GrandChild3", ParentId = 3 },
new Item { Id = 7, Name = "GrandChild4", ParentId = 3 },
new Item { Id = 8, Name = "Parent2", ParentId = 0 },
new Item { Id = 9, Name = "Child1", ParentId = 8 },
new Item { Id = 10, Name = "Child2", ParentId = 8 },
new Item { Id = 11, Name = "GrandChild1", ParentId = 9 },
new Item { Id = 12, Name = "GrandChild2", ParentId = 9 },
new Item { Id = 13, Name = "GrandChild3", ParentId = 10 },
new Item { Id = 14, Name = "GrandChild4", ParentId = 10 }
};
}
public static void Recursive(int parentId, List<string> ancestors)
{
List<Item> children = items.Where(x => x.ParentId == parentId).ToList();
if (children.Count == 0)
{
descendants.Add(string.Join(":", ancestors));
}
else
{
foreach (Item child in children)
{
List<String> newAncestors = new List<string>(ancestors);
newAncestors.Add(child.Name);
Recursive(child.Id, newAncestors);
}
}
}
}
}