当每个项目包含对其父项的引用时,从项列表中创建树

时间:2014-07-15 18:08:08

标签: c# linq tree

我有Foo类型的对象列表。每个Foo对象都包含对其父级的引用:

public class Foo
{
    public Foo Parent { get; set; }
}

(如果Parent为空,则Foo被视为“根”节点。)如您所见,这意味着一种“自下而上”的树层次结构。 / p>

我想通过将Foo个对象包装在一个名为TreeItem的新类中来颠倒这个子 - >父级关联;

public class TreeItem<T>
{
    public T Item { get; set; }
    public IEnumerable<TreeItem<T>> Children { get; set; }
}

如图所示,这将给我一个更自然的“自上而下”树层次结构。我相信这将允许更容易的数据绑定,例如。在WPF中TreeView

是否有一个简明的Linq语句可以获取List<Foo>,找到每个Foo对象的子项,并吐出相应转换的TreeItem<Foo>列表?

除了Linq查询,最简单的算法是什么?

奖金 :您将使用哪些字词或搜索字词来描述这种“树翻转”转换?

1 个答案:

答案 0 :(得分:6)

ToLookup可以轻松地为每个项目创建所有子项的查找。完成后,您可以将每个项目映射到新对象,并有一个简单的机制来获取每个项目的所有子项。

IEnumerable<Foo> data = GetData();
var lookup = data.ToLookup(foo => foo.Parent);
Func<Foo, TreeItem<object>> selector = null;
selector = foo => new TreeItem<object>()
{
    Item = foo,
    Children = lookup[foo].Select(selector),
};
var rootNodes = lookup[null].Select(selector);

或者,如果你宁愿避免递归,你可以在构建查找时转换每个项目而不映射子项,然后改变每个项目以便以后包含子项:

IEnumerable<Foo> data = GetData();
var lookup = data.ToLookup(foo => foo.Parent,
    foo => new TreeItem<object>() { Item = foo });
foreach (var node in lookup.SelectMany(x => x))
    node.Children = lookup[node.Item];
var rootNodes = lookup[null];

如果存在大量数据,则缺少递归可能很重要,并且它还允许它处理任意图形,而不仅仅是树。 (特别是它可以处理循环。)