vb.net - 在 VB.net 中使用 Linq 获取节点的所有子节点
问题描述
我有用于在 VB.Net 中填充 TreeList 的分层数据表,如下所示:
ID ParentID Name
----------------------
1 NUll a
2 NUll b
3 2 c
4 1 d
5 3 e
6 5 f
7 6 g
8 5 h
我的问题:如何在 vb.net 中使用 Linq 获取节点(ID)的所有子节点列表?请帮我。
解决方案
不幸的是,我对 VB 的了解不够好,无法为您提供 VB 答案。我将在 C# 中给出答案。你可能会理解这个想法。也许你可以添加你的 VB 翻译?
你忘了描述你的 Node 类。我假设您不仅想要孩子,还想要孙子(等)。
class TreeNode
{
public int Id {get; set;}
public string Name {get; set;}
// every node has zero or more sub-nodes:
public IEnumerable<TreeNode> Nodes {get; set;}
}
您希望您的层次结构达到未知的深度。因此,您不能使用标准 LINQ 函数。但是您可以轻松地扩展 LINQ 来创建自己的。请参阅扩展功能揭秘
public static IEnumerable<TreeNode> AsTreeNodes(this IEnumerable<Person> persons)
{
// Top TreeNodes: all persons without a Parent:
return persons.AsTreeNodes((int?)null);
}
使用递归返回所有具有 parentId 的人的节点序列的实际函数:
public static IEnumerable<TreeNode> AsTreeNodes(this IEnumerable<Person> persons, int? parentId)
{
// Top Nodes: all persons with parentId
var personsWithParentId = persons.Where(person.ParentId == parentId);
foreach (var person in personsWithParentId)
{
// every person will become one TreeNode with sub-nodes using recursion
TreeNode node = new TreeNode()
{
Id = person.Id,
Name = person.Name,
// get all my Children and Children's children:
Nodes = persons.ToNodeCollection(person.Id),
};
yield return node;
}
}
请注意,我选择返回 IEnumerable 而不是 List / Array。这样,只有在您真正枚举它们时才会创建项目。因此,如果您不想使用 ID 为 1 的人的节点,则不会创建他的所有孩子。
用法:获取“乔治华盛顿”所有后代的家族等级:
IEnumerable<Person> allPersons = ...
IEnumerable<TreeNode> allFamilyHierarchies = allPersons.AsTreeNodes();
IEnumerable<TreeNode> washingtonFamily = allFamilyHierarchies
.Where(familyHierarchy => familyHierarchy.Name == "George Washington");
注意:到目前为止,还没有创建 TreeNode,只创建了 IEnumerable。只要您执行不返回 IEnumerable 的操作,例如foreach
、ToList
、Any
、 ,枚举就会开始FirstOrDefault
。
因此,所有非华盛顿族将被忽略,不会创建顶级节点,也不会为其创建子节点。
如果您仔细观察,您会发现要查找所有子项,我必须枚举整个集合,以查找具有某个 ParentId 的所有人员。如果您首先将所有人员分组到具有相同 ParentId 的组中,然后将这些组放入以 ParentId 作为键的字典中,则可以更有效地完成此操作。这样可以非常快速地找到 ID 为 X 的父级的所有子级:
var personsWithSameParentId = persons.GroupBy(person => person.ParentId);
var dictionary = personsWithSameParentId.ToDictionary(group => group.Key)
字典中的每个元素都具有与 parentId 相等的键,并且所有具有此 parentId 的人都作为元素。
TreeNode CreateNodeForPerson(Person person)
{
IEnumerable<Person> children = dictionary[person.Id];
IEnumerable<TreeNode> childNodes = children
.Select(child => CreateNodeforPerson(child));
return new TreeNode()
{
Id = person.Id,
Name = person.Name,
Nodes = childNodes,
};
}
你会看到同样的递归。但是一旦你有了字典,你就不必枚举完整的 Person 集合,你只需访问你正在为其创建点头的 Person 的孩子/孩子的孩子等。
推荐阅读
- javascript - Cucumber JS:如何在 Given/When/Then 步骤之外导出/更新全局变量?
- sql - 在一个查询中选择不同的子类型值
- reactjs - UseContext 不迭代
- java - 行号错误 = inputLine.nextInt();
- python - 用于验证国际象棋王移动的 Python 代码
- javascript - Rails webpack js和ajax刷新
- javascript - 列制表器中的项目列表
- swift4 - 如何通过单击swift4中的addImage按钮将图像一张一张添加到tableviewcell中
- node.js - 使用 nodejs 解析结构化 JSON-LD 文件的问题
- node.js - 无法使用绝对文件路径导入 nodejs 模块(流星,linux。在 Windows 上工作正常)