Performance of nested yield in a tree

前端 未结 5 564
既然无缘
既然无缘 2020-11-28 12:20

I\'ve got a tree-like structure. Each element in this structure should be able to return a Enumerable of all elements it is root to. Let\'s call this method IEnumerabl

相关标签:
5条回答
  • 2020-11-28 12:46

    According to my prior experiences using yield is a lot more effective than creating a List. If you're using .NET 3.5, this implementation should be fine. But don't forget the

    yield break;
    

    At the end. :-)

    0 讨论(0)
  • 2020-11-28 12:53

    No, that looks fine.

    Have a look at my blog entry, it may be of some use :)

    0 讨论(0)
  • 2020-11-28 12:55

    You can improve performance if you unroll recurse to stack, so you will have only one iterator:

    public IEnumerable<Foo> GetAll()
    {
        Stack<Foo> FooStack = new Stack<Foo>();
        FooStack.Push(this);
    
        while (FooStack.Count > 0)
        {
            Foo Result = FooStack.Pop();
            yield return Result;
            foreach (Foo NextFoo in Result.MyChildren)
                FooStack.Push(NextFoo);
        }
    }
    
    0 讨论(0)
  • 2020-11-28 12:57

    A better solution might be to create a visit method that recursively traverses the tree, and use that to collect items up.

    Something like this (assuming a binary tree):

    public class Node<T>
    {
        public void Visit(Action<T> action)
        {
            action(this);
            left.Visit(action);
            right.Visit(action);
        }
    
        public IEnumerable<Foo> GetAll ()
        {
            var result = new List<T>();
            Visit( n => result.Add(n));
            return result;
        }
    }
    

    Taking this approach

    • Avoids creating large numbers of nested iterators
    • Avoids creating any more lists than necessary
    • Is relatively efficient
    • Falls down if you only need part of the list regularly
    0 讨论(0)
  • 2020-11-28 13:06

    It's certainly not ideal in terms of performance - you end up creating a lot of iterators for large trees, instead of a single iterator which knows how to traverse efficiently.

    Some blog entries concerning this:

    • Wes Dyer: All about iterators
    • Eric Lippert: Immutability in C#, part 6
    • Eric again: Immutability in C#, part 7

    It's worth noting that F# has the equivalent of the proposed "yield foreach" with "yield!"

    0 讨论(0)
提交回复
热议问题