我试图在几天没有进展的情况下解决这个问题,我的问题是:
给定层次结构中的实体,返回 一个直系列表的列表(或 实体的父 s )。
当我想知道“实体1.2.2.2”的层次结构时,它将返回一个仅包含粗体项的列表:
Entity 1 - Entity 1.1 - Entity 1.2 - Entity 1.2.1 - Entity 1.2.2 - Entity 1.2.2.1 - Entity 1.2.2.2 - Entity 1.2.3 - Entity 1.2.4 - Entity 1.2.4.1 - Entity 1.3 - Entity 1.4 Entity 2 ...
因此,预期结果:
Entity 1 - Entity 1.2 - Entity 1.2.2 - Entity 1.2.2.2
实施代码:
class Entity
{
public Entity Parent { get; set; }
public bool AbsoluteParent
{
get
{
return Parent == null;
}
}
public IEnumerable<Entity> Hierarchy //problem
{
get
{
return AbsoluteParent
? new [] { this }
: new [] { this }.Concat( Parent.Hierarchy );
}
}
}
上面的数组尝试只是我一直在尝试的选项之一,该代码实际上返回的内容如下:
Entity 1 Entity 1 - Entity 1.2 Entity 1 - Entity 1.2 - Entity 1.2.2 Entity 1 - Entity 1.2 - Entity 1.2.2 - Entity 1.2.2.2
我能够使用jQuery的parents()
函数实现预期的结果,我一直在阅读yield return
关键字,但仍然坚持其更多(我猜)功能风格,我还是宝贝 - 进入。
答案 0 :(得分:4)
迭代器块是否可以接受?
public IEnumerable<Entity> Hierarchy
{
// note: buffers results
get { return UpwardHierarchy.Reverse(); }
}
public IEnumerable<Entity> UpwardHierarchy
{
get
{
// genuine lazy streaming
for (var entity = this; entity != null; entity = entity.Parent)
yield return entity;
}
}
另一种选择:使用MoreLinq's Generate
:
return MoreEnumerable.Generate(this, entity => entity.Parent)
.TakeWhile(entity => entity != null)
.Reverse();
答案 1 :(得分:2)
当@Ani对他的回答发表评论时,无法从根本上获得一个懒惰的层次结构。
有一个有趣的manner of execution table将“Reverse()”方法显示为“延迟非流式执行”。所以它只在你访问它的第一个项目(root)时进行评估,但它需要读取整个UpwardHierarchy以产生第一个项目。
如果你想要表现,那么你应该注意的是linq(以及任何“yield return”方法)产生IEnumerable&lt;&gt;的方式。如果你要在Hierarchy上只迭代一次,那么可以忽略这个警告,但如果要多次搜索Hierarchy项,最好调用ToList()以避免重新处理UpwardHierarchy和“Reverse()” ”
一些代码:
[TestClass]
public class HierarchyTest
{
#region Ani's code
class Entity
{
public Entity Parent { get; set; }
public IEnumerable<Entity> Hierarchy
{
// note: buffers results
get { return UpwardHierarchy.Reverse(); }
}
public int YieldCount = 0;//modified
public IEnumerable<Entity> UpwardHierarchy
{
get
{
// genuine lazy streaming
for (var entity = this; entity != null; entity = entity.Parent)
{
YieldCount++;//modified
yield return entity;
}
}
}
}
#endregion
[TestMethod]
public void TestMethod1()
{
/*
Entity 1
- Entity 1.2
- Entity 1.2.2
- Entity 1.2.2.2
*/
var e1 = new Entity();
var e12 = new Entity() { Parent = e1 };
var e122 = new Entity() { Parent = e12 };
var e1222 = new Entity() { Parent = e122 };
var hierarchy = e1222.Hierarchy;
Assert.AreEqual(0, e1222.YieldCount);//nothing was evaluated until now
hierarchy.First();
Assert.AreEqual(4, e1222.YieldCount);//the entire UpwardHierarchy has been yielded to get the first Hierarchy item
hierarchy.First();
Assert.AreEqual(8, e1222.YieldCount);//yielded all UpwardHierarchy itens again to get the first Hierarchy item
List<Entity> evaluatedHierarchy = e1222.Hierarchy.ToList();//calling ToList() produces a List<Entity> instance so UpwardHierarchy and Reverse() are evaluated only once
Assert.AreEqual(12, e1222.YieldCount);//Yieldcount+=4 because of ToList()
evaluatedHierarchy.First();
Assert.AreEqual(12, e1222.YieldCount);//and now you can use evaluatedHierarchy as you wish without causing another UpwardHierarchy and Reverse() call.
evaluatedHierarchy.First();
Assert.AreEqual(12, e1222.YieldCount);
}
}
答案 2 :(得分:1)
这不是一种非常LINQ的方式(我的LINQ仍然很新):
List<Entity> graph = new List<Entity>()
Entity current = this;
while (current != null) {
graph.Add(current);
current = current.Parent;
}
graph.Reverse();
return graph;