Заполнение дерева из табличных данных без рекурсии

Предлагаю вашему вниманию альтернативный алгоритм построения дерева из данных документа или регистра. Этот способ позволяет без рекурсии построить иерархическую структуру данных. Для правильной работы у элемента данных должен быть ключ связи (родитель) и идентификатор элемента с где каталоги (узлы) младше элементов (файлов).

Идея заложена в неком контейнере, выпрямителе лесинки иерархических
данных в двумерный массив. В моём варианте этим контейнером служит
соответствие. Создаем контейнер, извлекаем данне запросом, сортируя по
идентификатору. Если данные собирались в таблицу с помощью рекурсивной
процедуры/функции, то узлы иерархии создаются раньше элемента,
соответственно идентификатор элемента всегда старше родительского узла.

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

// преобразует таблицу в дерево значений с помощью запроса (без рекурсии)
//
// Параметры
//  Документ  - ДокументСсылка - ссылка на документ табличную часть которого
//                 нужно преобразовать
//  ИмяТабЧасти  - Строка - Имя табличной части документа
//
//  ИмяПоляСортировки  - Строка - Имя поля табличной части документа по которому нужно сортировать данные
//                                      сортировка нужна для того чтобы данные перебирались от корня дерева
//
//  ИмяПризнакаКаталога  - Строка - Имя поля табличной части документа в котором хранится флаг каталога (узла)
//
//  ИмяРодительскгоПоля  - Строка - Имя поля табличной части документа в котором хранится номер радительского каталога (узла)
//
// Возвращаемое значение:
//   ДервеоЗначений   - результат преобразования
//
Функция ЗапросТаблицыПреобразованиеВДерево(     Документ,
ИмяТабЧасти,
ИмяПоляСортировки,
ИмяПризнакаКаталога,
ИмяРодительскгоПоля) Экспорт
//создаем соответствие куда будем складывать все строки признаком узла (ЭтоКаталог = Истина)
КонвертДляСтрок = Новый Соответствие;

//Создаем дерево и наполняем колонками
Древо = Новый ДеревоЗначений;
Для Каждого РеквизитТабЧасти Из Документ.Метаданные().ТабличныеЧасти[ИмяТабЧасти].Реквизиты Цикл
Древо.Колонки.Добавить(РеквизитТабЧасти.Имя, РеквизитТабЧасти.Тип);
КонецЦикла;

//извлекаем данные из табличной части документа
//сортировка задается по номеру строки, подразумевается, что узлы имеют более младший номер
//по сравнению с элементами. Именно в таком порядке рекурсивный опрос создает дерево, а мы работаем
//уже с готовым деревом
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
|       *
|ИЗ
|       &Документ КАК Источник
|ГДЕ
|       Источник.Ссылка = &Ссылка
|
|УПОРЯДОЧИТЬ ПО
|       Источник." + ИмяПоляСортировки;

Запрос.УстановитьПараметр("Ссылка", Документ.Ссылка);
Запрос.Текст = СтрЗаменить(Запрос.Текст, "&Документ", "Документ." + Документ.Метаданные().Имя + "." + ИмяТабЧасти);

Результат = Запрос.Выполнить();

ВыборкаДетальныеЗаписи = Результат.Выбрать();

Пока ВыборкаДетальныеЗаписи.Следующий() Цикл
//определяем каталог или элемент и для него определяем ветвь служащую родителем для элемента
Если ВыборкаДетальныеЗаписи[ИмяРодительскгоПоля] = 0 Тогда
Ветвь = Древо;
Иначе
Ветвь = КонвертДляСтрок.Получить(ВыборкаДетальныеЗаписи[ИмяРодительскгоПоля]);
КонецЕсли;
НовСтрокаДерева = Ветвь.Строки.Добавить();
ЗаполнитьЗначенияСвойств(НовСтрокаДерева, ВыборкаДетальныеЗаписи);
//вносим строку с каталогом (узлом) в двумерный список (Соответствие)
Если ВыборкаДетальныеЗаписи[ИмяПризнакаКаталога] Тогда
КонвертДляСтрок.Вставить(ВыборкаДетальныеЗаписи[ИмяПоляСортировки], НовСтрокаДерева);
КонецЕсли;
КонецЦикла;
Возврат Древо;
КонецФункции // ЗапросТаблицыПреобразованиеВДерево()

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

8 Comments

  1. Yashazz

    1. Зачем такой изврат, была конкретная нужда?

    2. Учите русский, ибо «лесИнка» это перебор;

    3. Круче Ильдаровича в этой теме никого нету.

    Reply
  2. makc2k

    (1) Yashazz, ЛесИнка потому что лесина — лесить жердины (по малоросски, а по белорусски дробына соответственно дробить), а если серьезно, то не хочу модераторов беспокоить пустяком. Данный алгоритм придумал сам без чьей либо помощи, а статья для закрепления в памяти.

    Reply
  3. gaglo

    А можно все-таки поподробнее, что это за документ, у которого в табличной части дерево, откуда оно туда попало и т.п.?

    Reply
  4. Makushimo

    (1) Yashazz,

    Ildarovich крут, не спорю

    но это, однако же, не бред

    забираю, спасибо автору

    Reply
  5. DAnry

    (2) что такое «по малоросски», это диалект какой-то? Может вы имели ввиду все же «по украински».

    Reply
  6. makc2k

    Кому как приятнее. Я бы сказал на одном из диалектов группы славянских языков.

    Аз — человек воплощенный на земле (в Сербском так и пишут АЗ — я), бога ведает, бога ведая, глаголит добро, есть живой …. Ну и так далее по азбуке.

    Дерево в документ я соорудил сам, это для удобства просмотра.

    Reply
  7. Патриот

    А «радительского» это от слова «ра», что по Задорновски означало «Солнце» у древних славян? =)

    Reply
  8. makc2k

    Родительского — от слова род, а радость — это ра в достатке. Задорнов не икона, не он это придумал. Все это еще 100 лет назад употребимо было.

    Reply

Leave a Comment

Ваш адрес email не будет опубликован. Обязательные поля помечены *