有没有办法简化这个反向枚举器?

问题描述

我们有一个案例,我们有一个层次树结构,我们需要获取任何特定节点的“分支”。该结构是一个从子到父的单向链表,但我们要定义从父到子的方向上的分支。

这是我们提出的实现的过度简化示例。只是想知道在考虑到这些限制的情况下是否有更好/更有效的方法来实现这一目标。我只是觉得这样做很冗长。

#nullable enable

public class Node {

    public Node(String name,Node? parent)
        => (Name,Parent) = (name,parent);

    public string Name   { get; set; }
    public Node?  Parent { get; init; }

    IEnumerable<Node> GetBranch(){
    
        static IEnumerable<Node> getBranchReversed(Node? node) { 
    
            while (node is not null) {
                yield return node;
                node = node.Parent;
            }
        }
    
        return getBranchReversed(this).Reverse();
    }
}

我能想到的唯一另一种方法是累加到一个列表中,我插入到第一个位置,然后返回列表(从我的记忆中输入这个,所以它可能无法编译......)

ReadOnlyCollection<Node> GetBranch(){

    Node? node = this;
    var branch = new List<Node>();

    while (node is not null) {
        branch.insert(0,node);
        node = node.Parent;
    }

    return branch.AsReadOnly();
}

再次,只是想知道是否还有其他方法可以实现这一目标。

解决方法

总结评论

IEnumerable.Reverse 或多或少执行以下操作

var buffer = new List<int>(ienumerableToReverse);
for (int i = buffer.count - 1; i >= 0; --i)
    yield return buffer.items[i];

需要注意的是,每次使用迭代器时它都会进行缓冲。它必须这样做,因为 IEnumerable 是懒惰的。如果你想保持懒惰的行为,这几乎是你能做的,无论你想使用什么解决方案,你都需要一个缓冲区。

如果你不想要懒惰的行为,我可能会自己做缓冲:

var branch = new List<Node>();

while (node is not null) {
    branch.Add(node);
    node = node.Parent;
}
branch.Reverse();
return branch;

这应该比您的示例更好,因为 Insert 需要为每个插入移动项目,导致二次缩放,而 .Reverse 是线性的。