Обход дерева значений с рекурсией и с заранее известным количество вложенных уровней
1.
Есть некоторое ДеревоЗначений, одно из полей (колонок) которого — «Количество». «Листья» дерева заполнены значениями, «узлы» содержат 0 (количество звездочек обозначает глубину вложенности):
* 0
* * 0
* * * 10
* * * 5
* * * 10
* * 0
* * * 0
* * * * 7
Необходимо «обойти» дерево, записав в поле «Количество» узлов сумму полей «Количество» подчиненных записей, т.е. в итоге должно получиться:
* 32
* * 25
* * * 10
* * * 5
* * * 10
* * 7
* * * 7
* * * * 7
Как будет решаться задача:
1. Если известно, что в дереве значений всего три уровня вложенности
2. Если количество уровней вложенности не ограничено.
Я вот напилил два варианта для известных уровней, но что-то не совсем работает, что первый, что второй, подскажите где я накасячил, спасибо.
&НаСервере Процедура Отобразить1НаСервере(ТабДок) Дерево = Новый ДеревоЗначений; Дерево.Колонки.Добавить("Количество",Новый ОписаниеТипов("Число")); ПерваяСтрока = Дерево.Строки.Добавить(); ПерваяСтрока.Количество = 0; ПерваяВтораяСтрока = ПерваяСтрока.Строки.Добавить(); ПерваяВтораяСтрока.Количество = 0; ПерваяТретяяСтрока = ПерваяВтораяСтрока.Строки.Добавить(); ВтораяТретяяСтрока = ПерваяВтораяСтрока.Строки.Добавить(); ТретяяТретяяСтрока = ПерваяВтораяСтрока.Строки.Добавить(); ПерваяТретяяСтрока.Количество = 10; ВтораяТретяяСтрока.Количество = 5; ТретяяТретяяСтрока.Количество = 10; ВтораяВтораяСтрока = ПерваяСтрока.Строки.Добавить(); ВтораяВтораяСтрока.Количество = 0; ВтораяВтораяТретяяСтрока = ВтораяВтораяСтрока.Строки.Добавить(); ВтораяВтораяТретяяСтрока.Количество = 0; ВтораяВтораяЧетвертаяСтрока = ВтораяВтораяТретяяСтрока.Строки.Добавить(); ВтораяВтораяЧетвертаяСтрока.Количество = 7; Макет = РеквизитФормыВЗначение("Объект").ПолучитьМакет("Макет"); ОблШапка = Макет.ПолучитьОбласть("ОблШапка"); ТабДок.Вывести(ОблШапка); Уровень= -1; ПерваяСтрокаД = Дерево.Строки; //первый вариант известных вложенных уровней. // Первый уровень подчиненных Для Каждого ПерваяСтрокаД Из ПерваяСтрокаД Цикл ПерваяСтрокаД.Количество = ПерваяСтрокаД.Количество; ПерваяВтораяСтрокаД = ПерваяСтрокаД.Строки; // Второй уровень подчиненных Для Каждого ПерваяВтораяСтрокаД Из ПерваяВтораяСтрокаД Цикл ПерваяВтораяСтрокаД.Количество = ПерваяВтораяСтрокаД.Количество+ПерваяСтрокаД.Количество; ПерваяТретяяСтрока = ПерваяВтораяСтрокаД.Строки; КонецЦикла; // Третий уровень подчиненных Для Каждого ПерваяТретяяСтрока Из ПерваяТретяяСтрока Цикл ПерваяТретяяСтрока.Количество = ПерваяВтораяСтрокаД.Количество + ПерваяТретяяСтрока.Количество КонецЦикла; // Второй уровень подчиненных 2 Для Каждого ВтораяВтораяСтрокаД Из ПерваяВтораяСтрокаД Цикл ВтораяВтораяСтрокаД.Количество = ВтораяВтораяСтрокаД.Количество+ПерваяСтрокаД.Количество; ТретяяПерваяСтрокаД = ВтораяВтораяСтрокаД.Строки; КонецЦикла; // Третий уровень подчиненных 2 Для Каждого ТретяяПерваяСтрокаД Из ТретяяПерваяСтрокаД Цикл ТретяяПерваяСтрокаД.Количество = ВтораяВтораяСтрокаД.Количество+ТретяяПерваяСтрокаД.Количество; ЧетвертаяПерваяСтрокаД = ТретяяПерваяСтрокаД.Строки; КонецЦикла; // Четвертый уровень подчиненных 2 Для Каждого ЧетвертаяПерваяСтрокаД Из ЧетвертаяПерваяСтрокаД Цикл ЧетвертаяПерваяСтрокаД.Количество = ЧетвертаяПерваяСтрокаД.Количество+ТретяяПерваяСтрокаД.Количество; КонецЦикла; КонецЦикла; // Второй вариант известных вложенных уровней // тут получается следующее // а 32 нету :( //* * 25 //* * * 10 //* * * 5 //* * * 10 //* * 7 //* * * 7 //* * * * 7 Для каждого ПерваяСтрокаД из Дерево.Строки Цикл Для каждого ПерваяВтораяСтрокаД из ПерваяСтрокаД.Строки Цикл ПерваяСтрокаД.Количество = ПерваяСтрокаД.Количество + ПерваяВтораяСтрокаД.Количество Для Каждого ПерваяТретяяСтрокаД из ПерваяВтораяСтрокаД.Строки Цикл ПерваяВтораяСтрокаД.Количество = ПерваяВтораяСтрокаД.Количество+ПерваяТретяяСтрокаД.Количество; КонецЦикла; КонецЦикла; Для каждого ВтораяВтораяСтрокаД из ПерваяСтрокаД.Строки Цикл Для каждого ВтораяВтораяТретяяСтрокаД из ВтораяВтораяСтрокаД.Строки Цикл Для каждого ВтораяВтораяЧетвертаяСтрокаД из ВтораяВтораяТретяяСтрокаД.Строки Цикл ВтораяВтораяЧетвертаяСтрокаД.Количество = ВтораяВтораяЧетвертаяСтрокаД.Количество; ВтораяВтораяТретяяСтрокаД.Количество = ВтораяВтораяЧетвертаяСтрокаД.Количество; ВтораяВтораяСтрокаД.Количество = ВтораяВтораяТретяяСтрокаД.Количество; ПерваяСтрокаД.Количество = ПерваяВтораяСтрокаД.Количество+ВтораяВтораяЧетвертаяСтрокаД.Количество; КонецЦикла; КонецЦикла; КонецЦикла; КонецЦикла; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ОблЭлемент = Макет.ПолучитьОбласть("ОблЭлемент"); //ОблЭлемент.Параметры.Количество = ВтораяВтораяСтрока.Количество+ПерваяВтораяСтрока.Количество; // //ТабДок.Вывести(ОблЭлемент); Для каждого СтрокаДереваЗначений из Дерево.Строки Цикл ВывестиСтрокуДерева(ОблЭлемент,Макет,ТабДок,СтрокаДереваЗначений,Уровень); КонецЦикла; КонецПроцедуры &НаКлиенте Процедура Отобразить1(Команда) Отобразить1НаСервере(Объект.ТабДок); КонецПроцедуры &НаСервере Функция ВывестиСтрокуДерева(ОблЭлемент,Макет,ТабДок,СтрокаДереваЗначений, Уровень) Для Каждого строкиД Из СтрокаДереваЗначений.Строки Цикл ОблЭлемент.Параметры.Количество = строкиД.Количество; ТабДок.Вывести(ОблЭлемент); ВывестиСтрокуДерева(ОблЭлемент,Макет,табДок,СтрокиД,Уровень+1); КонецЦикла; КонецФункции
Источник
1С 8.3 Дерево значений — Программист 1С Минск. Автоматизация бизнеса.
Дерево Значений в 1С 8.3 — это иерархический динамически набор любого типа. По своим функциям и структуре (колонки и строки) очень схожа с Таблицей Значений, но есть виртуальная колонка «Родитель». Дерево значений рекомендуется использовать для работы именно с иерархической информацией . Каждая строка дерева значений имеет свойства «Родитель» и «Строки», а также может иметь любое количество подчиненных строк. Операции с помощью встроенного функционала (сортировка, раскраска строк, поиск, итоги, различные отборы ) могут производится с учетом подчиненных строк / уровней иерархии.
&НаСервере
Процедура ЗаполнениеРеквизитаФормыДеревоЗначений ()
// Преобразование реквизита формы в объект прикладного типа ДеревоЗначений
ДеревоЗначений = РеквизитФормыВЗначение ( «ДеревоЗначНаФорме» );
// ДеревоЗначений = Новый ДеревоЗначений; — если без реквизита
ДЗ_Корень = ДеревоЗначений . Строки . Добавить ();
ДЗ_Корень . Наименование = «Самый верхний уровень» ;
ДЗ_1уровень = ДЗ_Корень . Строки . Добавить ();
ДЗ_1уровень . Наименование = «1-ая папка (группа)» ;
ЭлементДЗ_1 = ДЗ_1уровень . Строки . Добавить ();
ЭлементДЗ_1 . Наименование = «Первый (вложенный) элемент» ;
ДЗ_2уровень = ДЗ_Корень . Строки . Добавить ();
ДЗ_2уровень . Наименование = «2-ая папка (группа)» ;
ЭлементДЗ_1 = ДЗ_2уровень . Строки . Добавить ();
ЭлементДЗ_1 . Наименование = «Первый (вложенный) элемент» ;
ЭлементДЗ_2 = ДЗ_2уровень . Строки . Добавить ();
ЭлементДЗ_2 . Наименование = «Второй (вложенный) элемент» ;
// Преобразование ДеревоЗначений в реквизит формы (табличное поле)
ЗначениеВРеквизитФормы ( ДеревоЗначений , «ДеревоЗначНаФорме» );
&НаСервере
Процедура ЗаполнениеРеквизитаФормыДеревоЗначенийИзЗапроса ()
Запрос = Новый Запрос ;
Запрос . Текст = «ВЫБРАТЬ
| Материалы.Ссылка КАК Наименование
| Материалы.Родитель КАК Родитель
|ИЗ
| Справочник.Материалы КАК Материалы
|УПОРЯДОЧИТЬ ПО
| Наименование ИЕРАРХИЯ
|ИТОГИ ПО
| Родитель» ;
//Внимание! Если правильно не указать вид обхода результата выборки по запросу,
//то мы получим обычную таблицу значений
ДеревоЗначений = Запрос . Выполнить (). Выгрузить ( ОбходРезультатаЗапроса . ПоГруппировкамСИерархией );
// Заполнение дерева значений из результата запроса
// колонка «Материалы» – это элемент справочника, колонка «Родитель» – это группа
ЗначениеВРеквизитФормы ( ДеревоЗначений , «ДеревоЗначНаФорме» ); // Преобразование в реквизит формы (табличное поле)
&НаСервере
Процедура ПоискСтрокиВДеревеЗначений () // найдём 1-ю строку со значением «Элемент №1» в дереве значений
// Преобразование реквизита формы в объект прикладного типа ДеревоЗначений
ДеревоЗначений = РеквизитФормыВЗначение ( «ДеревоЗначНаФорме» );
// Поиск строки. (если строка не найдена, вернёт «Неопределено»)
НайденнаяСтрокаДЗ = ДеревоЗначений . Строки . Найти ( «Первый (вложенный) элемент» , «Наименование» , Истина);
// Анализ результата поиска
Если НайденнаяСтрокаДЗ = Неопределено Тогда
Сообщить ( «Строка не найдена» );
Иначе // вренёт первую найденную строку
Сообщить ( «Найдена: » + НайденнаяСтрокаДЗ . Наименование + » (» + НайденнаяСтрокаДЗ . Родитель . Наименование + «)» );
КонецЕсли;
&НаСервере
Процедура ПоискВсехСтрокВДеревеЗначений ()
// Преобразование реквизита формы в объект прикладного типа ДеревоЗначений
ДеревоЗначений = РеквизитФормыВЗначение ( «ДеревоЗначНаФорме» );
// Создаем структуру для поиска (условие)
НаименованиеДляПоиска = «Первый (вложенный) элемент» ;
ПараметрыОтбора = Новый Структура ;
ПараметрыОтбора . Вставить ( «Наименование» , НаименованиеДляПоиска );
// Поиск всех строк содержащих наименование «Первый (вложенный) элемент»
МассивСтрок_ДЗ = ДеревоЗначений . Строки . НайтиСтроки ( ПараметрыОтбора , Истина);
// Проверка найдены ли строки
Если МассивСтрок_ДЗ . Количество () = 0 Тогда
Сообщить ( «Ни одной строкис наименованием » + НаименованиеДляПоиска + » не найдено!» );
КонецЕсли;
// Перебор строк
Для Каждого Строка_ДЗ Из МассивСтрок_ДЗ Цикл
Если Строка_ДЗ . Родитель = Неопределено Тогда
Сообщить ( «Корень дерева значений: » + Строка_ДЗ . Наименование );
Иначе
Сообщить ( Строка_ДЗ . Наименование + » — » + Строка_ДЗ . Родитель . Наименование );
КонецЕсли
&НаСервере
Процедура УдалениеСтрокиИзДереваЗначений ()
// Преобразование реквизита формы в объект прикладного типа ДеревоЗначений
ДеревоЗначений = РеквизитФормыВЗначение ( «ДеревоЗначНаФорме» );
// С помощью данных методов возможно удаление конкретных строк
// Важно! При удалении либо очистки строки — все её подчинённые строки удалятся
// 1.Очистка всех строк
ДеревоЗначений . Строки . Очистить ();
// 2. Удаление по конкретному индексу
ДеревоЗначений . Строки . Удалить ( 0 );
// 3.Или удаление по конкретному наименованию
НайтиСтроку = ДеревоЗначений . Строки . Найти ( » Легированная сталь » , «Наименование» );
Если НЕ НайтиСтроку = Неопределено Тогда
ДеревоЗначений . Строки . Удалить ( НайтиСтроку );
КонецЕсли;
ЗначениеВРеквизитФормы ( ДеревоЗначений , «ДеревоЗначНаФорме» ); // Преобразование в реквизит формы (табличное поле)
Источник