【问题标题】:Create a Tree from a list of items, when each item contains a reference to its parent当每个项目都包含对其父项的引用时,从项目列表创建树
【发布时间】:2014-07-15 18:08:07
【问题描述】:

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

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

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

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

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

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

是否有简洁的 Linq 语句可以获取 List&lt;Foo&gt;,找到每个 Foo 对象的子对象,并吐出相应转换的 TreeItem&lt;Foo&gt; 列表?

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

奖励:您会使用什么词或搜索词来描述这种“树翻转”转换?

【问题讨论】:

    标签: c# linq tree


    【解决方案1】:

    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];
    

    如果有大量数据,递归的缺乏可能很重要,它还允许它处理任意图,而不仅仅是树。 (特别是它可以处理循环。)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-09-24
      • 1970-01-01
      • 1970-01-01
      • 2023-03-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多