【问题标题】:Is there a way to simplify this reverse-enumerator?有没有办法简化这个反向枚举器?
【发布时间】:2021-01-07 09:50:58
【问题描述】:

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

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

#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();
}

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

【问题讨论】:

  • 您可以使用for 循环而不是什么while,如果您愿意,可以节省1 行。最终,如果你想反转一个单链表,你需要缓冲它。 Reverse() 这样做,或者您可以手动完成(这将删除该本地功能并且可能会稍微快一些,尽管可能无法观察到),这并不重要
  • 在您的编辑中,我认为附加到列表然后将其反转会便宜很多,而不是不断碰撞所有元素(我认为这是二次的)
  • @canton7 这样反向不会在内部创建一个额外的缓冲区吗?那么这不是更大的内存压力吗?
  • 我认为插入是个好方法,但你也可以使用Stack&lt;T&gt;
  • 返回new List&lt;Node&gt;().Reverse() 不会创建一个新的缓冲区,只是一个反向枚举器。即使您就地颠倒了列表,那也是线性的。插入时,所有后续条目都必须复制到其右侧的插槽中,这是二次的

标签: c# linq ienumerable


【解决方案1】:

总结一下cmets

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 是线性的。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-06-22
    • 1970-01-01
    • 2019-04-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-12-01
    • 2020-07-07
    相关资源
    最近更新 更多