Быстрая конвертация Таблицы значений в Дерево значений и обратно

03.06.25

Разработка - Универсальные функции

Появилась задача по изменению и доработке данных в "ДеревеЗначений". Причем конфигурация и оболочка достаточно древние, так что БСП я сразу отбросил. Ниже представлены функции по конвертации соответствующих объектов.

Сложно себе представить ситуацию, когда бы понадобились подобные функции, но и тем не менее такой момент настал. Встала необходимость анализа уже собранных данных из "Дерева значений", а так же их доработка. После доработки данные нужно обратно загрузить в Дерево. Вот такая специфическая задача.

Глянув в интернете не нашел достойной реализации по этому представляю свой вариант ниже. 

 

Метод получения Таблицы значений из Дерева значений



// Преобразование ДеревоЗначений в ТаблицаЗначений
Функция ДеревоЗначенийВТаблицуЗначений(ДеревоЗначений, ДобавлятьКолонкуУровня = Истина) Экспорт
    
    ТаблицаЗначений = Новый ТаблицаЗначений;
    
    // Копируем колонки из дерева
    Для Каждого Колонка Из ДеревоЗначений.Колонки Цикл
        НоваяКолонка = ТаблицаЗначений.Колонки.Добавить(Колонка.Имя, Колонка.ТипЗначения, Колонка.Заголовок);
        НоваяКолонка.Ширина = Колонка.Ширина;
    КонецЦикла;
    
    // Добавляем служебные колонки для восстановления структуры
    ТаблицаЗначений.Колонки.Добавить("ИдентификаторСтроки", Новый ОписаниеТипов("УникальныйИдентификатор"));
    ТаблицаЗначений.Колонки.Добавить("ИдентификаторРодителя", Новый ОписаниеТипов("УникальныйИдентификатор"));
    
    Если ДобавлятьКолонкуУровня Тогда
        ТаблицаЗначений.Колонки.Добавить("УровеньБаза", Новый ОписаниеТипов("Число"));
    КонецЕсли;
    
    // Рекурсивно обходим дерево и заполняем таблицу
    ОбойтиСтрокиДерева(ДеревоЗначений.Строки, ТаблицаЗначений, Неопределено, 0, ДобавлятьКолонкуУровня);
    
    Возврат ТаблицаЗначений;
    
КонецФункции

// Вспомогательная процедура для рекурсивного обхода дерева
Процедура ОбойтиСтрокиДерева(СтрокиДерева, ТаблицаЗначений, ИдентификаторРодителя, УровеньБаза, ДобавлятьКолонкуУровня)
    
    Для Каждого СтрокаДерева Из СтрокиДерева Цикл
        
        НоваяСтрока = ТаблицаЗначений.Добавить();
        ИдентификаторТекущейСтроки = Новый УникальныйИдентификатор;
        
        // Копируем данные из строки дерева
        Для Каждого Колонка Из ТаблицаЗначений.Колонки Цикл
            Если Колонка.Имя <> "ИдентификаторСтроки" 
                И Колонка.Имя <> "ИдентификаторРодителя" 
                И Колонка.Имя <> "УровеньБаза" Тогда
                НоваяСтрока[Колонка.Имя] = СтрокаДерева[Колонка.Имя];
            КонецЕсли;
        КонецЦикла;
        
        // Заполняем служебные поля
        НоваяСтрока.ИдентификаторСтроки = ИдентификаторТекущейСтроки;
        НоваяСтрока.ИдентификаторРодителя = ИдентификаторРодителя;
        
        Если ДобавлятьКолонкуУровня Тогда
            НоваяСтрока.УровеньБаза = УровеньБаза;
        КонецЕсли;
        
        // Рекурсивно обрабатываем дочерние строки
        Если СтрокаДерева.Строки.Количество() > 0 Тогда
            ОбойтиСтрокиДерева(СтрокаДерева.Строки, ТаблицаЗначений, ИдентификаторТекущейСтроки, УровеньБаза + 1, ДобавлятьКолонкуУровня);
        КонецЕсли;
        
    КонецЦикла;
    
КонецПроцедуры

 

 

Метод получения  Дерева значений из Таблицы значений

 



// ИСПРАВЛЕННАЯ функция преобразования ТаблицаЗначений в ДеревоЗначений
Функция ТаблицуЗначенийВДеревоЗначений(ТаблицаЗначений) Экспорт
    
    ДеревоЗначений = Новый ДеревоЗначений;
    
    // Копируем колонки (исключая служебные)
    Для Каждого Колонка Из ТаблицаЗначений.Колонки Цикл
        Если Колонка.Имя <> "ИдентификаторСтроки" 
            И Колонка.Имя <> "ИдентификаторРодителя" 
            И Колонка.Имя <> "УровеньБаза" Тогда
            НоваяКолонка = ДеревоЗначений.Колонки.Добавить(Колонка.Имя, Колонка.ТипЗначения, Колонка.Заголовок);
            НоваяКолонка.Ширина = Колонка.Ширина;
        КонецЕсли;
    КонецЦикла;
    
    // Создаем соответствие для быстрого поиска строк по идентификатору
    СоответствиеСтрок = Новый Соответствие;
    
    // УБРАЛ сортировку - обрабатываем строки в исходном порядке!
    // Обрабатываем все строки в исходном порядке
    Для Каждого СтрокаТаблицы Из ТаблицаЗначений Цикл
        
        Если СтрокаТаблицы.ИдентификаторРодителя = Неопределено Тогда
            // Корневая строка
            НоваяСтрока = ДеревоЗначений.Строки.Добавить();
        Иначе
            // Ищем родительскую строку
            СтрокаРодитель = СоответствиеСтрок[СтрокаТаблицы.ИдентификаторРодителя];
            Если СтрокаРодитель <> Неопределено Тогда
                НоваяСтрока = СтрокаРодитель.Строки.Добавить();
            Иначе
                // Если родитель не найден, создаем как корневую
                НоваяСтрока = ДеревоЗначений.Строки.Добавить();
            КонецЕсли;
        КонецЕсли;
        
        // Копируем данные
        Для Каждого Колонка Из ДеревоЗначений.Колонки Цикл
            НоваяСтрока[Колонка.Имя] = СтрокаТаблицы[Колонка.Имя];
        КонецЦикла;
        
        // Сохраняем соответствие для поиска дочерних строк
        СоответствиеСтрок.Вставить(СтрокаТаблицы.ИдентификаторСтроки, НоваяСтрока);
        
    КонецЦикла;
    
    Возврат ДеревоЗначений;
    
КонецФункции

// УЛУЧШЕННАЯ альтернативная функция преобразования через уровни
Функция ТаблицуЗначенийВДеревоЗначенийПоУровням(ТаблицаЗначений) Экспорт
    
    ДеревоЗначений = Новый ДеревоЗначений;
    
    // Копируем колонки (исключая служебные)
    Для Каждого Колонка Из ТаблицаЗначений.Колонки Цикл
        Если Колонка.Имя <> "ИдентификаторСтроки" 
            И Колонка.Имя <> "ИдентификаторРодителя" 
            И Колонка.Имя <> "УровеньБаза" Тогда
            НоваяКолонка = ДеревоЗначений.Колонки.Добавить(Колонка.Имя, Колонка.ТипЗначения, Колонка.Заголовок);
            НоваяКолонка.Ширина = Колонка.Ширина;
        КонецЕсли;
    КонецЦикла;
    
    // Проверяем наличие колонки УровеньБаза
    КолонкаУровня = ТаблицаЗначений.Колонки.Найти("УровеньБаза");
    Если КолонкаУровня = Неопределено Тогда
        // Если нет колонки уровня, используем основную функцию
        Возврат ТаблицуЗначенийВДеревоЗначений(ТаблицаЗначений);
    КонецЕсли;
    
    // УБРАЛ сортировку - сохраняем исходный порядок строк!
    
    // Используем соответствие для поиска строк по идентификатору
    СоответствиеСтрок = Новый Соответствие;
    
    Для Каждого СтрокаТаблицы Из ТаблицаЗначений Цикл
        
        УровеньБаза = СтрокаТаблицы.УровеньБаза;
        
        Если УровеньБаза = 0 Тогда
            // Корневая строка
            НоваяСтрока = ДеревоЗначений.Строки.Добавить();
        Иначе
            // Ищем родительскую строку по идентификатору
            СтрокаРодитель = СоответствиеСтрок[СтрокаТаблицы.ИдентификаторРодителя];
            
            Если СтрокаРодитель <> Неопределено Тогда
                НоваяСтрока = СтрокаРодитель.Строки.Добавить();
            Иначе
                // Если родитель не найден, создаем как корневую
                НоваяСтрока = ДеревоЗначений.Строки.Добавить();
            КонецЕсли;
        КонецЕсли;
        
        // Копируем данные
        Для Каждого Колонка Из ДеревоЗначений.Колонки Цикл
            НоваяСтрока[Колонка.Имя] = СтрокаТаблицы[Колонка.Имя];
        КонецЦикла;
        
        // Сохраняем соответствие для поиска дочерних строк
        СоответствиеСтрок.Вставить(СтрокаТаблицы.ИдентификаторСтроки, НоваяСтрока);
        
    КонецЦикла;
    
    Возврат ДеревоЗначений;
    
КонецФункции

 

Также отмечу, что решение внедрено в реальную базу, оно рабочее, так что пользуйтесь. )

ДеревоЗначений в ТаблицуЗначений Таблица значений в дерево значений

См. также

Универсальные функции Программист 1С v8.3 1C:Бухгалтерия Бесплатно (free)

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

21.05.2024    35469    dimanich70    83    

155

Универсальные функции Программист 1С v8.3 1C:Бухгалтерия Абонемент ($m)

Задача: вставить картинку из буфера обмена на форму средствами платформы 1С.

1 стартмани

18.03.2024    5466    6    John_d    11    

57

Универсальные функции Программист Стажер 1С v8.3 1C:Бухгалтерия Бесплатно (free)

Пришлось помучиться с GUID-ами немного, решил поделиться опытом, мало ли кому пригодится.

12.02.2024    41642    atdonya    29    

63

Универсальные функции Программист 1С v8.3 Бесплатно (free)

На заключительных этапах, когда идет отладка или доработка интерфейса, необходимо много раз переоткрыть внешний объект. Вот один из способов автоматизации этого.

30.11.2023    7081    ke.92@mail.ru    17    

66

WEB-интеграция Универсальные функции Механизмы платформы 1С Программист 1С v8.3 1C:Бухгалтерия Бесплатно (free)

При работе с интеграциями рано или поздно придется столкнуться с получением JSON файлов. И, конечно же, жизнь заставит проверять файлы перед тем, как записывать данные в БД.

28.08.2023    19335    YA_418728146    8    

173

Пакетная печать Печатные формы Адаптация типовых решений Универсальные функции 1С v8.3 1С:ERP Управление предприятием 2 1С:Управление торговлей 11 1С:Комплексная автоматизация 2.х Россия Абонемент ($m)

Расширение для программ 1С:Управление торговлей, 1С:Комплексная автоматизация, 1С:ERP, которое позволяет распечатывать печатные формы для непроведенных документов. Можно настроить, каким пользователям, какие конкретные формы документов разрешено печатать без проведения документа.

2 стартмани

22.08.2023    5300    86    progmaster    13    

4

Инструментарий разработчика Универсальные функции 1С v8.3 1С:Бухгалтерия 3.0 1С:ERP Управление предприятием 2 1С:Управление холдингом 1С:Зарплата и Управление Персоналом 3.x 1С:Комплексная автоматизация 2.х 1С:Управление нашей фирмой 3.0 1С:Управление торговлей 11 1С:Розница 2 1С:Розница 3.0 1С:Документооборот Абонемент ($m)

Копирует в буфер значения из списков, из ячеек отчетов, таблиц, настроек списков, других отборов и вставляет в выбранную настройку отбора. Работает с Объект не найден. Работает как в одной так и между разными базами 1С. Использует комбинации [Alt+C] Копировать список, [Alt+V] Вставить список. Также для копирования данных используется стандартная [Ctrl+C] (например из открытого xls, mxl, doc и т.п. файла скопировать список наименований)

1 стартмани

13.10.2022    20869    206    sapervodichka    113    

138
Комментарии
Подписаться на ответы Инфостарт бот Сортировка: Древо развёрнутое
Свернуть все
1. Sashares 33 03.06.25 12:03 Сейчас в теме
// Копируем данные из строки дерева
Для Каждого Колонка Из ТаблицаЗначений.Колонки Цикл
Если Колонка.Имя <> "ИдентификаторСтроки"
И Колонка.Имя <> "ИдентификаторРодителя"
И Колонка.Имя <> "УровеньБаза" Тогда
НоваяСтрока[Колонка.Имя] = СтрокаДерева[Колонка.Имя];
КонецЕсли;
КонецЦикла;


Зачем это делать для каждой строки дерева? Почему не получить 1 раз имена нужных колонок и заполнить сразу?

И не понял, зачем столько служебных колонок.
Можно добавить одну колонку - строка родитель, и заполнять в нее строку этой же ТЧ, которая соответствует строке родителя дерева.
5. ltfriend 04.06.25 07:00 Сейчас в теме
(1) зачем вообще получать список колонок, когда достаточно использовать ЗаполнитьЗначенияСвойств.
7. Sashares 33 04.06.25 09:54 Сейчас в теме
(5) чтобы не заполнять служебные
9. dhurricane 05.06.25 08:19 Сейчас в теме
(7) Они ведь потом ниже переопределяются, так что не страшно.
10. user700522_lerner584 08.06.25 20:01 Сейчас в теме
(7) Да к на это есть 4-ый параметр данного метода, в котором указывается перечень игнорируемых колонок.
2. andrew.ab 226 03.06.25 12:10 Сейчас в теме
в чем быстрота метода? Где замеры, где сравнение с другими методами?
BigB; skeptik2105; orakool; Sashares; +4 Ответить
3. aximo 2357 03.06.25 14:18 Сейчас в теме
прикол... в древние времена сам всякое писал - типа "читалки любого dbf в таблицу" https://infostart.ru/1c/tools/89298/

а сейчас все это готовенькое есть наверноое....
4. user613549_scratch_sv 03.06.25 22:49 Сейчас в теме
Быстрая?
Функция ТаблицаЗначенийВДеревоЗначений(ТЗ, ГруппировкаКолонки, ИтогКолонки) Экспорт
ПЗ = Новый ПостроительЗапроса;
ПЗ.ИсточникДанных = Новый ОписаниеИсточникаДанных(ТЗ);//передаем ТЗ
ПЗ.ДобавлениеПредставлений = ТипДобавленияПредставлений.НеДобавлять;
Для каждого Поле Из СтрРазделить(ГруппировкаКолонки, ", ", Ложь) Цикл
ПЗ.ИсточникДанных.Колонки[Поле].Измерение = Истина;//по этой колонке идет группировка
КонецЦикла;
Для каждого Поле Из СтрРазделить(ИтогКолонки, ", ", Ложь) Цикл
ПЗ.ИсточникДанных.Колонки[Поле].Итог = "Сумма("+Поле+")";
КонецЦикла;
ПЗ.ЗаполнитьНастройки();
ПЗ.Выполнить();
Дерево = ПЗ.Результат.Выгрузить(ОбходРезультатаЗапроса.ПоГруппировкамСИерархией);
Возврат Дерево;
КонецФункции

и обратно:

Дерево.Колонки.Добавить("__врПоле", Новый ОписаниеТипов("Булево"));
ТЗ = Новый ТаблицаЗначений;
Для каждого Поле Из Дерево.Колонки Цикл ТЗ.Колонки.Добавить(Поле.Имя, Поле.ТипЗначения); КонецЦикла;
Для каждого Ст Из Дерево.Строки.НайтиСтроки(Новый Структура("__врПоле", Ложь), Истина) Цикл ЗаполнитьЗначенияСвойств(ТЗ.Добавить(), ст); КонецЦикла;
ТЗ.Колонки.Удалить("__врПоле");
6. RustIG 1884 04.06.25 09:08 Сейчас в теме
1) есть прямой, симметричный и обратный обход дерева - у вас какой?
2) иногда нужно не обходить дерево , а найти что-то. Для поиска используется обход дерева "в глубину" или " в ширину"...

ПС. Андрей, извините за оффтопик, я давно не писал статьи - сколько сейчас начисляют за написание статей?
8. kuzyara 2158 04.06.25 10:29 Сейчас в теме
(6) https://infostart.ru/journal/news/mir-1s/izmenenie-v-pravilakh-ustarevshie-stati-v-baze-znaniy-bolshe-ne-budut-zarabatyvat-startmani_1914927/
- за публикацию статей объемом больше 10 000 знаков автор получает 10 стартмани
- если статья набирает больше 50 баллов, мы начисляем автору еще 30 стартмани
- если статья набирает больше 100 баллов, автор получает 20 стартмани
- если статья набирает более 500 баллов, за каждую последующую тысячу “лайков” от читателей, мы начислим автору 10 стартмани.
Оставьте свое сообщение