我已经设置了这个编程练习。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication2
{
class DataObject {
public int ID { get; set; }
public int ParentID { get; set; }
public string Data { get; set; }
public DataObject(int id, int pid, string data) { this.ID = id; this.ParentID = pid; this.Data = data; }
}
class TreeNode {
public DataObject Data {get;set;}
public List<DataObject> Children { get; set; }
}
class Program
{
static void Main(string[] args)
{
List<DataObject> data = new List<DataObject>();
data.Add(new DataObject(1, 0, "Item 1"));
data.Add(new DataObject(2, 0, "Item 2"));
data.Add(new DataObject(21, 2, "Item 2.1"));
data.Add(new DataObject(22, 2, "Item 2.2"));
data.Add(new DataObject(221, 22, "Item 2.2.1"));
data.Add(new DataObject(3, 0, "Item 3"));
}
}
}
所需的输出是3个treenode的列表,包含项目1,2和3.项目2将包含2个数据对象的列表作为其子成员,依此类推。
我一直在尝试使用LINQ中的1个语句填充这棵树(或者更确切地说是森林)。一个简单的组可以提供所需的数据,但挑战在于将它组织在TreeNode对象中。
有人可以为此提供暗示或不可能的结果吗?
答案 0 :(得分:1)
LINQ对递归数据结构的效果不是很好,但你可以近距离接触。
由于您可能想要一个任意深度的树,我将更改您对Children的定义,并为构造函数添加一个辅助方法,该方法将执行使树构建LINQ语句成为可能所需的递归。
class TreeNode
{
public DataObject Data { get; set; }
public List<TreeNode> Children { get; private set; }
public TreeNode(DataObject data)
{
Data = data;
Children = new List<TreeNode>();
}
//name chosen to match XElement method. I would name this
//SelfAndDescendants or change the behavior to match the name.
public IEnumerable<TreeNode> DescendantsAndSelf()
{
return (new TreeNode[] { this }).Concat(from c in this.Children
from sc in c.DescendantsAndSelf()
select sc);
}
}
现在我们可以定义以下方法:
public static TreeNode BuildTree(IEnumerable<DataObject> items, int rootId)
{
var root = new TreeNode(new DataObject(rootId, int.MinValue, "Root"));
return (from i in items
let n = new TreeNode(i)
group n by n.Data.ParentID into nodeGroup
orderby nodeGroup.Key ascending
select nodeGroup)
.Aggregate(root, (parent, childGroup) =>
{
parent.DescendantsAndSelf()
.First(n => n.Data.ID == childGroup.Key)
.Children.AddRange(childGroup);
return parent;
});
}
这种方法做了一些假设,但应该让你朝着正确的方向前进。
OrderBy
+ Aggregate
将项目推送到树中).First()
调用将抛出异常)。答案 1 :(得分:0)
如果你只想要两层树,那就相当简单了:
var roots = from root in data
where !data.Any(d => root.ParentID == d.ID)
select new TreeNode
{
Data = root,
Children = data.Where(d => d.ParentID == root.ID).ToList(),
}