代码之家  ›  专栏  ›  技术社区  ›  Francisco Aquino

获取层次结构中实体的父级

  •  2
  • Francisco Aquino  · 技术社区  · 14 年前

    我的问题是:

    给定层次结构中的实体,返回 直接提升者名单(或 起源 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 关键词,但仍然停留在它更多的(我猜)功能风格,我仍然婴儿步入。

    3 回复  |  直到 14 年前
        1
  •  1
  •   GrayWizardx    14 年前

    不是一种很好的LINQ方式(我的LINQ还是很新的):

    List<Entity> graph = new List<Entity>()
    Entity current = this;
    
    while (current != null) {
       graph.Add(current);
       current = current.Parent;
    }
    
    graph.Reverse();
    
    return graph;
    
        2
  •  4
  •   Ani    14 年前

    迭代器块可以接受吗?

    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();
    
        3
  •  2
  •   AntonioR    14 年前

    正如@ani对他的答案所作的评论,没有办法从根目录中获取一个懒惰的层次结构。

    有一个有趣的 manner of execution table 它将“reverse()”方法显示为“延迟的非流式执行”。因此,它只在您访问它的第一个项(根)时评估,但它需要读取整个向上的层次结构来生成第一个项。

    如果您希望获得性能,您应该支付的注意事项是Linq(以及任何“yield return”方法)生成IEnumerable的方式。如果只在层次结构上迭代一次,则可以忽略此警报,但如果要多次搜索层次结构项,最好调用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);
        }
    }