Linq查询,用于从树结构中选择一个项目,但要从整体上看 [英] Linq query for selecting an item from tree structure, but to look in the whole depth

查看:85
本文介绍了Linq查询,用于从树结构中选择一个项目,但要从整体上看的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是我上的课:

public class ItemTree
{

    public Int32 id { get; set; }

    [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
    public String text { get; set; }

    [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
    public List<ItemTree> item { get; set; }

    public int parentId { get; set; }

}

这是我的用法:

var tree = new ItemTree();
tree.id = 0;
tree.text = "sometext";
tree.item = new List<ItemTree>();

foreach (...)
{
    if (tree.item.Count == 0)
    {
      tree.item.Add(new ItemTree
      {
        id = my_id,
        text = my_name,
        item = new List<ItemTree>(),
        parentId = my_par
      });
    }
    else
    {
      tree.item.Where(x => x.id == my_par)
               .Select(x => x.item)
               .First()
               .Add(new ItemTree 
               {
                 id = my_id,
                 text = my_name,
                 item = new List<ItemTree>(),
                 parentId = my_par
               });
    }
}

它在Where子句的行中崩溃. 它崩溃的原因是:树上有一个项目,其中有一个项目列表,而我的查询仅检查树的第一个项目,而不是他的孩子.

And it crashes in the line with the Where clause. the reason it crashes is this: the tree has one item who has a list of items, and my query only checks the first item of the tree, not his children.

如何在树的整个深度中搜索并在其中添加项目?

How to search in the whole depth of the tree and add an item there?

推荐答案

将树结构展平为列表可能很方便.如果仅具有包含树的所有节点的IEnumerable<ItemTree>,则某些逻辑将更易于表达.您不会丢失任何信息,因为每个节点上仍然有父ID.

It might be convenient to flatten your tree structure into a list. Some logic will be easier to express if you just have an IEnumerable<ItemTree> that contains all the nodes of your tree. You're not losing any information, since you still have the parent ID on every node.

这是自然的递归问题.使用递归lambda,尝试类似的操作:

This is a naturally recursive problem. Using a recursive lambda, try something like:

Func<ItemTree, IEnumerable<ItemTree>> flattener = null;
flattener = t => new[] { t }
                .Concat(t.item == null 
                        ? Enumerable.Empty<ItemTree>()
                        : t.item.SelectMany(child => flattener(child)));

请注意,当您像这样进行递归Func时,必须首先分别声明Func并将其设置为null.

Note that when you make a recursive Func like this, you must declare the Func separately first, and set it to null.

您还可以使用迭代器块方法将列表展平:

You could also flatten the list using an iterator-block method:

public static IEnumerable<ItemTree> Flatten(ItemTree node)
{
    yield return node;
    if (node.item != null)
    {
         foreach(var child in node.item)
             foreach(var descendant in Flatten(child))
                 yield return descendant;
    }
}

无论哪种方式,一旦树被展平,您都可以在展平的列表上执行简单的Linq查询以找到节点:

Either way, once the tree is flattened you can do simple Linq queries over the flattened list to find nodes:

flattener(tree).Where(t => t.id == my_id);

然后,为了添加到树中,您可以执行以下操作:

Then, in order to add to the tree, you can do:

var itemOfInterest = flattenedTree.Where(t => t.id == myId).Single();
itemOfInterest.item = itemOfInterest.item ?? new List<ItemTree>();
itemOfInterest.item.Add(myItemToAdd);

其中flattenedTree是使用我们的两种展平策略之一生成的.

Where flattenedTree was generated using one of our two flattening strategies.

我还想指出,item对于列表属性不是一个好名字.此类属性通常是复数的(items).同样,属性通常是大写的(Items).

I also want to note that item is not a great name for a property that is a list. Such properties are most often pluralized (items). Also, properties are usually capitalized (Items).

这篇关于Linq查询,用于从树结构中选择一个项目,但要从整体上看的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆