powered by simpleCommunicator - 2.0.51     © 2025 Programmizd 02
Форумы / WinForms, .Net Framework [игнор отключен] [закрыт для гостей] / Сделать дерево плоским списком
25 сообщений из 38, страница 1 из 2
Сделать дерево плоским списком
    #39695059
Qwe.Qwe1
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Есть класс, хранящий дерево элементов. Дочерние элементы хранятся в поле списка List<BaseTreeData> Child . Хочу вывести это дерево как "плоский" (линейный) список всех элементов. После разделения класса на два (базовый и наследник) метод GetChildren выдают ошибку про несоответствие типов. Скорее всего все логично, но как это исправить?

Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
namespace ConsoleApplication1
{
    class Program
    {        
        static void Main(string[] args)
        {
            var data = new List<TreeData>();
            for (int i = 0; i < 5; i++)
            {
                var item = new TreeData() { Name = i.ToString() };
                for (int j = 0; j < 3; j++)
                {
                    var number = (i + 1) * 10 + j;
                    item.Child.Add(new TreeData() { ID = number, Name = number.ToString(), Parent = item });                    
                }
                data.Add(item);
            }

            foreach (var item in data.SelectMany(x => GetChildren(x)))
            {
                Console.WriteLine(item.ID + " " + item.Name + " " + item.IsChecked);
            }
        }

        static IEnumerable<TreeData> GetChildren(TreeData d)
        {
            return new[] { d }.Concat(d.Child).SelectMany(x => GetChildren(x));
        }
    }

    class BaseTreeData
    {
        public bool IsChecked { get; set; }
        public BaseTreeData Parent { get; set; }
        public List<BaseTreeData> Child { get; set; }

        public BaseTreeData()
        {
            Child = new List<BaseTreeData>();
        }
    }

    class TreeData : BaseTreeData
    {
        public int ID { get; set; }
        public string Name { get; set; }
    }
}
...
Рейтинг: 0 / 0
Сделать дерево плоским списком
    #39695066
Roman Mejtes
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
        public static IEnumerable<T> GetAll<T>(T item, Func<T, IEnumerable<T>> getChild)
        {
            yield return item;
            foreach (var i in getChild(item))
            {
                foreach (var j in GetAll(i, getChild))
                {
                    yield return j;
                }
            }
        }
...
Рейтинг: 0 / 0
Сделать дерево плоским списком
    #39695089
Qwe.Qwe1
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
А как вызывать? А можно сделать этот метод - методом расширения?
...
Рейтинг: 0 / 0
Сделать дерево плоским списком
    #39695158
Roman Mejtes
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
using System;
using System.Collections.Generic;

namespace TreeEnumerableExample
{
    class Program
    {
        static void Main(string[] args)
        {
            var treeItem = new TreeItem("A1")
            {
                Children =
                {
                    new TreeItem("B1")
                    {
                        Children =
                        {
                            new TreeItem("C1")
                            {
                                Children =
                                {
                                    new TreeItem("D1"),
                                    new TreeItem("D2"),
                                }
                            }
                        }
                    },
                    new TreeItem("B2")
                    {
                        Children =
                        {
                            new TreeItem("C2")
                        }
                    }
                }
            };

            foreach (var i in TreeEx.GetAll(treeItem, p=>p.Children))
            {
                Console.WriteLine(i.Name);
            }

            Console.ReadKey();
        }
    }

    public class TreeItem
    {
        public TreeItem(string name)
        {
            Name = name;
            Children = new List<TreeItem>();
        }
        public string Name { get; }
        public List<TreeItem> Children { get; }
    }

    public class TreeEx
    {
        public static IEnumerable<T> GetAll<T>(T item, Func<T, IEnumerable<T>> getChild)
        {
            yield return item;
            foreach (var i in getChild(item))
            {
                foreach (var j in GetAll(i, getChild))
                {
                    yield return j;
                }
            }
        }

        public static IEnumerable<T> GetAll<T>(IEnumerable<T> items, Func<T, IEnumerable<T>> getChild)
        {
            foreach (var i in items)
            {
                foreach (var j in GetAll(i, getChild))
                {
                    yield return j;
                }
            }
        }
    }
}
...
Рейтинг: 0 / 0
Сделать дерево плоским списком
    #39695339
Qwe.Qwe1
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Спасибо. А зачем второй метод GetAll? И как быть, если я класс дерева унаследую (см. код ниже), как привести тип при вызове
foreach (var i in TreeEx.GetAll(treeItem, p => p.Children))

Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
public class TreeItem2 : TreeItem
{
    public string Address { get; set; }

    public TreeItem2() : base (null) { }
    public TreeItem2(string name) : base(name) { }
    public TreeItem2(string name, string address) : base(name)
    {
        Address = address;
    }
}

var treeItem = new TreeItem2("A1")
{
    Children =
    {
        new TreeItem2("B1")
        ...
...
Рейтинг: 0 / 0
Сделать дерево плоским списком
    #39695376
Фотография hVostt
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Roman Mejtes,

лучше избегать рекурсии, без крайней необходимости
...
Рейтинг: 0 / 0
Сделать дерево плоским списком
    #39695449
Фотография ЕвгенийВ
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
hVosttRoman Mejtes,

лучше избегать рекурсии, без крайней необходимости
А как тут избежишь?
...
Рейтинг: 0 / 0
Сделать дерево плоским списком
    #39695450
Roman Mejtes
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
hVostt,

опасность есть только в переполнении стека, если дерево не супер глубокое и не имеет циклических ссылок, когда потомки ссылаются на предка в качестве свою потомков, проблем не будет.
...
Рейтинг: 0 / 0
Сделать дерево плоским списком
    #39695484
ViPRos
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Roman Mejtes,

все это ужасно медленно
...
Рейтинг: 0 / 0
Сделать дерево плоским списком
    #39695493
Roman Mejtes
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ЕвгенийВhVosttRoman Mejtes,

лучше избегать рекурсии, без крайней необходимости
А как тут избежишь?
Создаете очередь\коллекцию вершин которые нужно обойти. Добавляете в неё Root ветку.
Запускаете цикл до тех пор пока коллекция вершин не будет пуста.
В цикле извлекаете элемент из очереди\коллекции элемент и возвращаете его через yield return, после чего добавляете все его ветки в очередь\коллекцию. Затем повторяете так до тех пор, пока цикл не закончится. Профит.
Преимущество этого способа в том, что вы не зависите от размера стека и глубины дерева.

Примерно вот так:
Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
        public static IEnumerable<T> GetAllWithOutRecursion<T>(T item, Func<T, IEnumerable<T>> getChild)
        {
            Queue<T> queue= new Queue<T>();
            queue.Enqueue(item);
            while (itemsForScan.Count > 0)
            {
                var currentItem = queue.Dequeue();
                foreach (var i in getChild(currentItem))
                {
                    queue.Enqueue(i);
                }
                yield return currentItem;
            }
        }
...
Рейтинг: 0 / 0
Сделать дерево плоским списком
    #39695496
Фотография hVostt
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ЕвгенийВА как тут избежишь?

https://docs.microsoft.com/ru-ru/dotnet/api/system.collections.stack
...
Рейтинг: 0 / 0
Сделать дерево плоским списком
    #39695505
Фотография hVostt
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Roman Mejtes,

лучше использовать коллекцию Stack, а не очередь :)
...
Рейтинг: 0 / 0
Сделать дерево плоским списком
    #39695510
Фотография hVostt
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Исправил. Убрал ненужное заталкивание в очередь/стек всех элементов для извлечения. Только целые коллекции.

Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
        public static IEnumerable<T> GetAllWithOutRecursion<T>(T item, Func<T, IEnumerable<T>> getChild)
        {
            var stack = new Stack<IEnumerable<T>>();
            stack.Push(new[] {item});
            while (stack.Count > 0)
            {
                var items = stack.Pop();
                foreach (var item in items)
                {
                    yield return item;                    
                    stack.Push(getChild(item));
                }
            }
        }
...
Рейтинг: 0 / 0
Сделать дерево плоским списком
    #39695512
Фотография hVostt
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ViPRosвсе это ужасно медленно

Потестим на Benchamark.NET :)
...
Рейтинг: 0 / 0
Сделать дерево плоским списком
    #39695527
Roman Mejtes
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
hVostt,

я делал на коленке в процессе между сборками проекта :) сейчас работы очень много, у тебя косяк в коде
2 раза подряд в одной области видимости определяется переменная item
T item и var item, а так всё ок :)
...
Рейтинг: 0 / 0
Сделать дерево плоским списком
    #39695597
Фотография hVostt
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Roman Mejtes,

рабочий код так и пишем, всё на коленке
шутка
...
Рейтинг: 0 / 0
Сделать дерево плоским списком
    #39695618
Фотография ЕвгенийВ
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
hVosttИсправил. Убрал ненужное заталкивание в очередь/стек всех элементов для извлечения. Только целые коллекции.

Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
        public static IEnumerable<T> GetAllWithOutRecursion<T>(T item, Func<T, IEnumerable<T>> getChild)
        {
            var stack = new Stack<IEnumerable<T>>();
            stack.Push(new[] {item});
            while (stack.Count > 0)
            {
                var items = stack.Pop();
                foreach (var item in items)
                {
                    yield return item;                    
                    stack.Push(getChild(item));
                }
            }
        }


А как сюда добавить асинхронную блокировку по значению?
...
Рейтинг: 0 / 0
Сделать дерево плоским списком
    #39695632
Фотография hVostt
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ЕвгенийВ,

Троллишь чтоли?
...
Рейтинг: 0 / 0
Сделать дерево плоским списком
    #39695660
Фотография ЕвгенийВ
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
hVosttЕвгенийВ,

Троллишь чтоли?
Так, для поднятия настроения. :)

А вот тут можно обойтись без рекурсии?
Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
  public class A
    {
        public IEnumerable<B> Items { get; set; }
    }
    public class B
    {
        public IEnumerable<C> Items { get; set; }
    }
    public class C
    {
        public IEnumerable<A> Items { get; set; }
    }
    public class C1
    {
        public void Run(A a)
        {
            //обработка a
            //...........
            foreach (var b in a.Items)
            {
                Run(b);
            }
        }
        public void Run(B b)
        {
            //обработка b
            //...........
            foreach (var c in b.Items)
            {
                Run(c);
            }
        }
        public void Run(C c)
        {
            //обработка c
            //...........
            foreach (var a in c.Items)
            {
                Run(a);
            }
        }
    }
...
Рейтинг: 0 / 0
Сделать дерево плоским списком
    #39695664
Roman Mejtes
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
для этого нужно использовать наследование, а элементы в стеке могут иметь тип Object, а наследники можно получать через условие по типу
...
Рейтинг: 0 / 0
Сделать дерево плоским списком
    #39695806
Фотография hVostt
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ЕвгенийВ,

Визитор ))
...
Рейтинг: 0 / 0
Сделать дерево плоским списком
    #39695854
Фотография ЕвгенийВ
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
hVosttЕвгенийВ,

Визитор ))

Вот попробуй как нибудь отнаследоваться от ExpressionVisitor , хотя бы тупо переопределить виртуальные методы простым вызовом базового и посмотреть в отладчике стек вызовов.
Не пойдет визитор :)
...
Рейтинг: 0 / 0
Сделать дерево плоским списком
    #39695930
Фотография hVostt
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ЕвгенийВ,

Так в этом и смысл. При добавлении класса, его нужно добавить в интерфейс посетителя, что неумолимо приведёт к необходимости написать реализацию. К сожалению, функциональщики этого факта не понимают, по этому со своим аргументом "код в три строки" идут лесом :)

Визитор может обойти иерархию и сделать что-нибудь, нахаляву получишь сформированный плоский список.
...
Рейтинг: 0 / 0
Сделать дерево плоским списком
    #39695966
Фотография ЕвгенийВ
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
hVostt,
Визитор обойдет иерархию с использованием взаимной рекурсии.
...
Рейтинг: 0 / 0
Сделать дерево плоским списком
    #39696195
Фотография hVostt
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ЕвгенийВ,

Визитор тут нужен не для рекурсии, а для извлечения из объекта X, коллекции, если она вообще там есть. Это будет реализация визитора для построения плоского списка из иерархии любой вложенности.
...
Рейтинг: 0 / 0
25 сообщений из 38, страница 1 из 2
Форумы / WinForms, .Net Framework [игнор отключен] [закрыт для гостей] / Сделать дерево плоским списком
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]