首页 > 解决方案 > 返回具有分配的所有子项的新列表的函数 VS 返回该列表的子项但未分配的函数

问题描述

我正在尝试找出一种方法来遍历对象的所有子项(包括子项的子项)而不创建垃圾分配。

我之前的函数是一个返回列表的递归函数。

现在我有两个函数,一个返回一个计数,另一个在某个索引处获取孩子。

我觉得可能有更好的方法来遍历一个对象的所有孩子

这是一个比较递归列表和递归计数 + getAt(index) 的示例代码


public class MyClassWithChildren
{
    private MyClassWithChildren[] m_Children;

    //With allocation
    public IReadOnlyList<MyClassWithChildren> GetAllChildren(bool includeThis = false)
    {
        var allChildren = new List<MyClassWithChildren>();
        if (includeThis) {
            allChildren.Add(this);
        }

        if (m_Children != null) {
            for (int i = 0; i < m_Children.Length; i++) {
                allChildren.AddRange(m_Children[i].GetAllChildren(true));
            }
        }
        return allChildren;
    }


    //Without allocation combination of count and getAt(index) 


    public int GetAllChildrenCount(bool includeThis = false)
    {
        var count = 0;
        if (includeThis) { count++; }

        for (int i = 0; i < m_Children.Length; i++) {
            count += 1 + m_Children[i].GetAllChildrenCount();
        }

        return count;
    }

    public MyClassWithChildren GetAllChildrenAt(int index, bool includeThis = false)
    {

        if (includeThis) {
            if (index == 0) { return this;}
            index--;
        }

        for (int i = 0; i < m_Children.Length; i++) {
            if (index == 0) { return m_Children[i]; }

            index--;

            var newIndex = index - m_Children[i].GetAllChildrenCount(false);
            if (newIndex < 0) { return m_Children[i].GetAllChildrenAt(index); }

            index = newIndex;
        }

        return null;
    }
}

有谁知道更好的方法来做到这一点?一个简单的用例是搜索某个对象是否是另一个对象的子对象。另一种方法是找到所有具有特定属性值的孩子。

感谢您的时间

标签: c#

解决方案


也许这就是您正在寻找的:

public IEnumerable<MyClassWithChildren> GetAllChildren()
{
    var items = new Queue<MyClassWithChildren>();
    items.Enqueue(this);

    while (items.TryDequeue(out var result))
    {
        yield return result;

        for (var i = 0; i < result.m_children.Length; ++i) // use for instead of foreach to avoid enumerator creation
        {
            items.Enqueue(result.m_children[i]);
        }
    }
}

这将在外部循环处理它并请求下一个返回值之后评估返回值的子代。这意味着所有孩子都是惰性迭代的。如果您的外部循环将在第一个元素之后停止,则只有该元素已被排入结果队列。枚举数没有开销,m_children因为此代码使用for-loop 而不是foreach-loop。

如果您需要所有元素的计数 - 只需使用 linq: GetAllChildren().Count()


推荐阅读