问题描述
我有一个指向自身的X类实例的集合(自我引用).
作为一个例子,我的课看起来像这样:
I have a collection of class X instances that point to themselves (self-referencing).
As an example, my class could look like this:
public class X {
string Name {get;set;}
List<X> Children {get;}
}
现在可以说我有一个X类实例的列表,这些实例可以将自己向下N级进行自我引用.
Now lets say I have a list of instances of class X, which can self-reference themselves N levels down.
我的问题是:如何从列表中的第N个级别获得X的实例?
基本上,我试图在C#中做一个递归自引用公共表表达式在SQL中的工作,这是为了弄平一个添加级别编号的层次结构列表.
Basically I am trying to do in C# what a recursive self-referencing common table expression would do in SQL, which is to flatten out a hierarchical list adding level numbers.
我找到了以下示例: https://stackoverflow.com/a/2118192/1171461 效果很好,但我仍然想不出如何仅从Nth级别获取元素.
I have found this example: https://stackoverflow.com/a/2118192/1171461That works great but I still cant figure out how to get the elements ONLY from Nth level.
推荐答案
好吧,您可以修改链接示例中的Flatten
方法,使其还包括一个级别编号,如下所示:
Well, you can modify the Flatten
method in the linked example to include a level number as well, along these lines:
public class Leveled<T>
{
public T Item {get; set;}
public int Level {get; set;}
}
public static IEnumerable<Leveled<T>> ToLeveled<T>(this IEnumerable<T> sequence,
int level)
{
return sequence.Select(item => new Leveled<T>{ Item = item, Level = level});
}
public static IEnumerable<Leveled<T>> FlattenLeveled<T>(this IEnumerable<T> sequence,
Func<T, IEnumerable<T>> childFetcher)
{
var itemsToYield = new Queue<Leveled<T>>(sequence.ToLeveled(0));
while (itemsToYield.Count > 0)
{
var leveledItem = itemsToYield.Dequeue();
yield return leveledItem;
var children = childFetcher(leveledItem.Item).ToLeveled(leveledItem.Level + 1);
if (children != null)
{
foreach (var child in children)
itemsToYield.Enqueue(child);
}
}
}
在此之后,您可以过滤出所需的级别:
after this, you can just filter out the required level:
var thirdLevel = myCollection
.FlattenLeveled(item => item.Children)
.Where(leveledItem => leveledItem.Level == 2)
.Select(leveledItem => leveledItem.Item)
此外,根据@Servy的评论,由于这是广度优先的方法(在处理第二级之前完成第一级的所有操作),因此我们可以使用Skip/TakeWhile,如下所示:
Also, from @Servy's comment, since this is a breadth first approach (all of 1st level get done before any of the 2nd level is processed), we can use Skip/TakeWhile, like this:
public static IEnumerable<T> GetHierarchyLevel<T>(this IEnumerable<T> sequence, Func<T, IEnumerable<T>> childFetcher, int level)
{
return sequence.FlattenLeveled(childFetcher)
.SkipWhile(li => li.Level < level)
.TakeWhile(li => li.Level == level)
.Select(li => li.Item);
}
这会延迟地进行枚举,因此根本不会处理层次结构后面的任何级别.
This will enumerate lazily, so any level further down the hierarchy will not be processed at all.
这篇关于展平(带有级别编号)层次结构列表的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!