Перечисление Наборов, которые не являются по сути IEnumerable?

Узел является частью дерева DOM, Элемент является конкретным типом Узла

, например, <foo> This is Text </foo>

у Вас есть Элемент нечто, (который является также Узлом, поскольку Элемент наследовался Узлу), и текстовый Узел, 'Это - текст', который является ребенком Элемента/Узла нечто

22
задан Community 23 May 2017 в 10:29
поделиться

5 ответов

Этот код должен помочь

public static class Extensions
{
    public static IEnumerable<T> GetRecursively<T>(this IEnumerable collection,
        Func<T, IEnumerable> selector)
    {
        foreach (var item in collection.OfType<T>())
        {
            yield return item;

            IEnumerable<T> children = selector(item).GetRecursively(selector);
            foreach (var child in children)
            {
                yield return child;
            }
        }
    }
}

Вот пример его использования

TreeView view = new TreeView();

// ...

IEnumerable<TreeNode> nodes = view.Nodes.
    .GetRecursively<TreeNode>(item => item.Nodes);

Обновление: В ответ на сообщение Эрика Липперта.

Вот значительно улучшенная версия используя метод, описанный в Все об итераторах .

public static class Extensions
{
    public static IEnumerable<T> GetItems<T>(this IEnumerable collection,
        Func<T, IEnumerable> selector)
    {
        Stack<IEnumerable<T>> stack = new Stack<IEnumerable<T>>();
        stack.Push(collection.OfType<T>());

        while (stack.Count > 0)
        {
            IEnumerable<T> items = stack.Pop();
            foreach (var item in items)
            {
                yield return item;

                IEnumerable<T> children = selector(item).OfType<T>();
                stack.Push(children);
            }
        }
    }
}

Я провел простой тест производительности, используя следующую методику тестирования производительности . Результаты говорят сами за себя. Глубина дерева имеет лишь незначительное влияние на производительность второго решения; тогда как производительность быстро снижается для первого решения, что в конечном итоге приводит к StackOverflowException , когда глубина дерева становится слишком большой.

benchmarking

32
ответ дан 29 November 2019 в 03:53
поделиться

Я не уверен насчет TreeNodes, но вы можете сделать коллекцию Controls формы IEnumerable, используя System.Linq и, например,

var ts = (from t in this.Controls.OfType<TextBox>
                 where t.Name.Contains("fish")
                 select t);
//Will get all the textboxes whose Names contain "fish"

Извините, что говорю Я не знаю, как сделать это рекурсивным, в голову не приходит.

2
ответ дан 29 November 2019 в 03:53
поделиться

На основе решения Мриденгрена:

public static IEnumerable<T> GetRecursively<T>(this IEnumerable collection,
    Func<T, IEnumerable> selector,
    Func<T, bool> predicate)
{
    foreach (var item in collection.OfType<T>())
    {
        if(!predicate(item)) continue;

        yield return item;

        IEnumerable<T> children = selector(item).GetRecursively(selector, predicate);
        foreach (var child in children)
        {
            yield return child;
        }
    }
}


var theNodes = treeView1.Nodes.GetRecursively<TreeNode>(
    x => x.Nodes,
    n => n.Text.Contains("1")).ToList();

Изменить: для BillW

2
ответ дан 29 November 2019 в 03:53
поделиться

Думаю, вы просите что-то вроде этого.

public static IEnumerable<T> <T,TCollection> GetNodesRecursively(this TCollection nodeCollection, Func<T, TCollection> getSub)
 where T, TCollection: IEnumerable
{   
    foreach (var theNode in )
    {
        yield return theNode;
        foreach (var subNode in GetNodesRecursively(theNode, getSub))
        {
            yield return subNode;
        }
    }
}

var all_control = GetNodesRecursively(control, c=>c.Controls).ToList();
1
ответ дан 29 November 2019 в 03:53
поделиться

Похоже, вы на правильном пути, и в приведенных выше ответах есть несколько хороших идей. Но отмечу, что все эти рекурсивные решения имеют глубокие недостатки.

Предположим, что в рассматриваемом дереве всего n узлов с максимальной глубиной дерева d <= n.

Во-первых, они занимают пространство стека системы в глубине дерева. Если древовидная структура очень глубокая, это может привести к сбою стека и сбою программы. Глубина дерева d равна O (lg n), в зависимости от коэффициента ветвления дерева. В худшем случае - никакого ветвления - только связанный список - и в этом случае дерево с несколькими сотнями узлов разнесет стек.

Во-вторых, вы создаете итератор, который вызывает итератор, который вызывает итератор ... так, чтобы каждый MoveNext () на верхнем итераторе фактически выполнял цепочку вызовов, которая снова является O (d) в Стоимость. Если вы сделаете это на каждом узле, то общая стоимость вызовов составит O (nd), что в худшем случае O (n ^ 2) и в лучшем случае O (n lg n). Вы можете добиться большего, чем оба; нет причин, по которым это не может быть линейным во времени.

Уловка состоит в том, чтобы перестать использовать небольшой хрупкий системный стек, чтобы отслеживать, что делать дальше, и начать использовать стек, выделенный кучей, для явного отслеживания.

Вы должны добавить в свой список чтения статью Уэса Дайера по этому поводу:

https://blogs.msdn.microsoft.com/wesdyer/2007/03/23/all-about-iterators/

Он дает несколько хороших техник в конце для написания рекурсивных итераторов.

хрупкий системный стек, чтобы отслеживать, что делать дальше, и начать использовать выделенный в куче стек для явного отслеживания.

Вы должны добавить в свой список чтения статью Уэса Дайера по этому поводу:

https://blogs.msdn.microsoft.com/wesdyer/2007/03/23/all-about-iterators/

Он дает несколько хороших техник в конце для написания рекурсивных итераторов.

хрупкий системный стек, чтобы отслеживать, что делать дальше, и начать использовать выделенный в куче стек для явного отслеживания.

Вы должны добавить в свой список чтения статью Уэса Дайера по этому поводу:

https://blogs.msdn.microsoft.com/wesdyer/2007/03/23/all-about-iterators/

Он дает несколько хороших техник в конце для написания рекурсивных итераторов.

22
ответ дан 29 November 2019 в 03:53
поделиться
Другие вопросы по тегам:

Похожие вопросы: