从树结构的每个级别获取属性
本文关键字:获取 属性 结构 | 更新日期: 2023-09-27 18:35:44
我有一个对象列表,其中列表中的每个对象可能在其下方具有另一个相同类型的列表(一个非常标准的树结构)。我正在寻找一种方法来通常从这棵树的每个级别中提取一个属性(因为我想潜在地将其中的几个)拉入扁平列表。
对象示例:
public class Group {
public List<Group> SubGroups { get; set; }
public List<OtherStuff> OtherStuffs { get; set; }
public OtherThing Thing { get; set; }
}
这样:
groups.FlattenProperty(g => g.Thing)
但仍然能够
groups.FlattenProperty(g => g.OtherStuffs).SelectMany(s => s);
我对数据结构没有太多控制权,因为它是遗留系统的一部分,因此修改结构实际上不是一种选择。
是否有可合理重用的现有解决方案?
我相信
这就是你要找的。
public static IEnumerable<T> FlattenProperty<T>(this Group g, Func<Group,T> transform)
{
yield return transform(g);
foreach(var item in g.SubGroups.SelectMany(sub => sub.FlattenProperty(transform)))
yield return item;
}
这会获取您的 lambda 并将其应用于初始Group
对象并生成结果。 然后它将递归地调用自己为SubGroups
. SelectMany
将从递归调用返回的IEnumerable
中提取单个项目,并且每个项目都将被喊出。
或者,如果您想传入IEnumerable<Group>
则可以将其更改为
public static IEnumerable<T> FlattenProperty<T>(
this IEnumerable<Group> groups,
Func<Group,T> transform)
{
foreach(Group g in groups)
{
yield return transform(g);
foreach(var item in g.SubGroups.FlattenProperty(transform))
yield return item;
}
}
对 juharr 的答案稍作调整,允许我最终使用的任意对象。
public static IEnumerable<TV> FlattenTreeProperty<T, TV>(this IEnumerable<T> collectionToRecurse, Func<T, IEnumerable<T>> childrenSelector, Func<T, TV> propertySelector)
{
var itemsToRecurse = (collectionToRecurse != null ? collectionToRecurse as IList<T> ?? collectionToRecurse.ToList() : new List<T>());
if (!itemsToRecurse.Any())
{
yield break;
}
foreach (var item in itemsToRecurse.Select(propertySelector).Where(i => i != null))
{
yield return item;
}
foreach (var itemList in itemsToRecurse.Select(childrenSelector).Where(i => i != null))
{
foreach (var item in itemList.FlattenTreeProperty(childrenSelector, propertySelector))
{
yield return item;
}
}
}
像这样使用:
groups.FlattenTreeProperty(g => g.SubGroups, g => g.OtherStuffs)
在它上面超载清理它给了我我想要的东西。
编辑:修复了稀疏树,如果任何子项为空,SelectMany 会引发异常