Как реализовать отбор и поиск в дереве значений в 1С

Программист 1С v8.3 (Обычные формы) IT и автоматизация бизнеса
← На главную

Работа с иерархическими структурами данных, такими как ДеревоЗначений, всегда сопряжена с определенными трудностями при реализации поиска или отбора. В отличие от плоских таблиц, в дереве недостаточно просто скрыть строку — необходимо учитывать связь между родительскими и дочерними узлами. Если дочерний элемент соответствует критериям поиска, то и все его родители должны остаться видимыми, чтобы дерево не "рассыпалось".

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

Метод 1. Программная фильтрация через рекурсивный обход

Этот способ считается классическим и наиболее гибким. Его суть заключается в том, что мы создаем копию исходного дерева или работаем с оригиналом, удаляя строки, не соответствующие условию. Рассмотрим подробнее алгоритм «Снизу Вверх», который позволяет сохранить целостность иерархии.

Почему именно снизу вверх? Если мы начнем удалять родителей сразу, мы потеряем доступ к их детям. Если же мы сначала проверим «листья» (самый нижний уровень), мы сможем определить, нужно ли оставлять родителя.

Проанализируем пример функции, которая рекурсивно очищает дерево от строк, не подходящих под условие:


Процедура ФильтроватьДерево(СтрокиДерева, ЗначениеПоиска)
    
    МассивНаУдаление = Новый Массив;
    
    Для Каждого Строка Из СтрокиДерева Цикл
        
        // Рекурсивно заходим в подчиненные строки
        Если Строка.Строки.Количество() > 0 Тогда
            ФильтроватьДерево(Строка.Строки, ЗначениеПоиска);
        КонецЕсли;
        
        // Проверяем: если после очистки детей у строки нет и сама она не подходит
        // под условие — добавляем её в массив на удаление
        ПодходитПодУсловие = Найти(НРег(Строка.НоменклатураНаименование), НРег(ЗначениеПоиска)) > 0;
        
        Если НЕ ПодходитПодУсловие И Строка.Строки.Количество() = 0 Тогда
            МассивНаУдаление.Добавить(Строка);
        КонецЕсли;
        
    КонецЦикла;
    
    Для Каждого СтрокаДляУдаления Из МассивНаУдаление Цикл
        СтрокиДерева.Удалить(СтрокаДляУдаления);
    КонецЦикла;
    
КонецПроцедуры

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

Метод 2. Использование метода НайтиСтроки

Объект КоллекцияСтрокДереваЗначений обладает встроенным методом НайтиСтроки. Он работает достаточно быстро, но имеет важную особенность: он возвращает массив ссылок на строки, а не новое дерево. Если мы просто очистим исходное дерево, ссылки в массиве станут недействительными.

Рассмотрим правильный подход с использованием копирования:

  1. Создаем копию полного дерева методом Скопировать().
  2. Используем метод НайтиСтроки для поиска нужных элементов в оригинале.
  3. Переносим найденные элементы в чистое дерево, восстанавливая иерархию (это трудоемкий процесс).

Гораздо эффективнее использовать НайтиСтроки для идентификации объектов, которые НУЖНО удалить, как это предлагалось в обсуждении на форуме:


// Пример отбора "Пустых" позиций
Отбор = Новый Структура("Количество", 0);
МассивСтрок = ДеревоДанных.Строки.НайтиСтроки(Отбор, Истина); // Параметр Истина включает поиск по всем уровням

Для Каждого Стр Из МассивСтрок Цикл
    Попытка
        Стр.Родитель.Строки.Удалить(Стр);
    Исключение
        ДеревоДанных.Строки.Удалить(Стр); // Если это верхний уровень
    КонецПопытки;
КонецЦикла;

Метод 3. Отбор через Построитель запроса

Как отметили участники обсуждения, ПостроительЗапроса — это мощный инструмент для работы с данными. Он умеет накладывать стандартные 1С-овские фильтры. Однако напрямую ДеревоЗначений он воспринимает не всегда корректно (часто «схлопывает» до плоской таблицы).

Чтобы этот метод сработал, рекомендуется использовать в качестве источника данных не само дерево, а запрос, который это дерево формирует. В тексте запроса следует использовать конструкцию {ГДЕ ...}. Тогда вы сможете программно передать настройки отбора, и на выходе получить уже отфильтрованный результат запроса методом Выгрузить(ОбходРезультатаЗапроса.ПоГруппировкам).


Построитель = Новый ПостроительЗапроса;
Построитель.Текст = 
    "ВЫБРАТЬ
    |   Номенклатура.Ссылка КАК Номенклатура,
    |   Количество КАК Кол
    |ИЗ
    |   Справочник.Номенклатура КАК Номенклатура
    |{ГДЕ
    |   Номенклатура.Ссылка.* КАК Номенклатура}";

Построитель.ЗаполнитьНастройки();
// Здесь пользователь или программист задает отбор
НовыйОтбор = Построитель.Отбор.Добавить("Номенклатура");
НовыйОтбор.ВидСравнения = ВидСравнения.ВИерархии;
НовыйОтбор.Использование = Истина;

Построитель.Выполнить();
ДеревоРезультат = Построитель.Результат.Выгрузить(ОбходРезультатаЗапроса.ПоГруппировкамИИерархии);

Метод 4. Визуальный отбор через Условное оформление (Управляемые формы)

Если вы работаете на платформе 8.3 с управляемыми формами, можно обойтись без удаления строк. Это сохранит целостность данных и повысит производительность. Для быстрой генерации правил отображения элементов формы можно использовать конструктор кода условного оформления.

Выясним, как это реализовать:

  1. Добавим в ДеревоЗначений служебную колонку Видимость (тип Булево).
  2. Программным циклом (аналогично Методу 1) обойдем дерево и проставим Истина для тех строк, которые должны быть видны.
  3. В свойствах таблицы формы настроим Условное оформление: если Видимость равно Ложь, то установить параметр Видимость в значение Ложь для всей строки.

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

Метод 5. Использование штатной «Строки поиска»

Начиная с версии платформы 8.3.15, у элемента формы Таблица (при отображении дерева) появилось свойство Строка поиска. Если его включить, платформа сама отрисует поле ввода. При вводе текста 1С автоматически отфильтрует дерево, показывая только совпадения и их родителей. Это самый быстрый способ, не требующий написания кода, но он ограничен только простым текстовым поиском по видимым колонкам.

Резюме и рекомендации

Выбор конкретного метода зависит от вашей конфигурации и сложности условий:

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

← На главную