К статье
Практический материал

Разработка и Конфигурация · 10 мин

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

Как отсортировать дерево значений в 1С: метод Сортировать(), сортировка по уровням, по нескольким колонкам, типичные ошибки и примеры кода на встроенном языке.

Дерево значений в 1С — иерархическая структура данных, где у каждой строки могут быть подчинённые строки. В отличие от таблицы значений, простая сортировка здесь осложняется тем, что порядок нужно наводить на каждом уровне иерархии отдельно, а иногда — перестраивать саму структуру дерева. Встроенный язык предоставляет для этого метод Сортировать(), но у него есть особенности, которые нужно учитывать.

Типичные задачи, где требуется сортировка дерева: вывод иерархического справочника в отчёт в алфавитном порядке, упорядочивание строк по сумме или количеству, подготовка данных для отображения в элементе формы «Дерево значений». Во всех этих случаях важно понимать, сортируется ли только текущий уровень или вся вложенность, и что происходит с подчинёнными строками при перестановке родителей.

Как устроена сортировка дерева значений

Объект ДеревоЗначений содержит коллекцию строк верхнего уровня, а каждая строка — собственную коллекцию подчинённых строк. Метод Сортировать() доступен и у самого дерева, и у коллекции строк любого узла. Это даёт два принципиально разных сценария: сортировка всего дерева целиком и сортировка строк внутри конкретного узла.

Ключевое свойство метода: при сортировке строки перемещаются целиком, вместе со всеми своими подчинёнными ветками. Структура иерархии не разрушается — родительская строка просто меняет позицию среди «соседей», унося с собой дочерние элементы. Это отличает сортировку от перестроения дерева, где меняются сами связи «родитель–потомок».

Базовый синтаксис метода Сортировать()

Метод вызывается у дерева или у коллекции строк и принимает строку с параметрами сортировки:

Дерево.Сортировать("Наименование");

По умолчанию сортировка выполняется по возрастанию и затрагивает все уровни иерархии: сначала упорядочиваются строки верхнего уровня, затем рекурсивно — строки каждого узла. Для сортировки по убыванию добавьте модификатор Убыв:

Дерево.Сортировать("Сумма Убыв");

Второй необязательный параметр — СортироватьПоИерархии (булево). Если передать Ложь, будет отсортирован только текущий уровень коллекции, у которой вызван метод, без обхода вложенных строк. Это полезно, когда подчинённые уровни должны сохранить исходный порядок.

Сортировка по нескольким колонкам

Когда одного поля недостаточно — например, сначала нужно упорядочить по группе, а внутри группы по наименованию — колонки перечисляются через запятую в порядке приоритета:

Дерево.Сортировать("Группа Возр, Наименование Возр, Сумма Убыв");

Сравнение выполняется последовательно: если значения первой колонки равны, строки сравниваются по второй, и так далее. Учитывайте типы данных колонок: строки сравниваются лексикографически с учётом регистра, числа и даты — по значению. Если в колонке смешанные типы, результат может быть неожиданным, поэтому перед сортировкой стоит привести данные к единому типу через ОписаниеТипов при создании колонки.

Признак корректной многоуровневой сортировки: строки с одинаковым значением первой колонки идут подряд, а внутри таких блоков соблюдается порядок по второй колонке. Если блоки «перемешаны», проверьте, нет ли в данных лишних пробелов или разного регистра в сортируемом поле.

Сортировка отдельных уровней иерархии

На практике часто нужно отсортировать только строки верхнего уровня или только дочерние строки конкретного узла. Для этого метод вызывается у нужной коллекции:

// Только верхний уровень, вложенные не трогаем

Дерево.Строки.Сортировать("Наименование", Ложь);

// Сортировка строк внутри конкретного узла

Для Каждого СтрокаВерхнегоУровня Из Дерево.Строки Цикл

СтрокаВерхнегоУровня.Строки.Сортировать("Сумма Убыв", Истина);

КонецЦикла;

Второй параметр Истина у коллекции строк означает, что сортировка распространится на все нижележащие уровни этого узла. Такой подход даёт гибкость: на одном уровне можно сортировать по алфавиту, на другом — по сумме.

Порядок действий для типовой сортировки
  1. 1
    Убедитесь, что колонка, по которой сортируете, существует и имеет однородный тип данных.
  2. 2
    Вызовите Дерево.Сортировать("Колонка Возр") для сортировки всего дерева.
  3. 3
    Если нужен один уровень — вызовите Сортировать() у коллекции Строки нужного узла с параметром Ложь.
  4. 4
    Проверьте результат: порядок на каждом уровне и сохранность связей родитель–потомок.
  5. 5
    Если дерево выведено на форму, убедитесь, что отображение обновилось.

Сортировка дерева, отображаемого на форме

Если дерево значений является реквизитом формы и отображается в табличном поле, сортировка выполняется тем же методом — программно, например в обработчике команды или при нажатии на заголовок колонки. После вызова Сортировать() элемент формы обычно обновляется автоматически, так как данные реквизита изменились.

Важный нюанс: у дерева на форме может быть развёрнуто состояние узлов. После сортировки развёрнутость, как правило, сохраняется, поскольку строки остаются теми же объектами, но если вы пересоздаёте дерево заново — состояние развёрнутости теряется, и его нужно восстанавливать вручную, запомнив ключевые значения развёрнутых строк до перестроения.

Для интерактивной сортировки по щелчку на заголовок удобно хранить текущее направление в переменной и чередовать Возр/Убыв при повторном нажатии на ту же колонку.

bsl
Процедура СортироватьДеревоПоКолонке(ИмяКолонки)
    Если ТекущаяКолонка = ИмяКолонки Тогда
        Направление = ?(Направление = "Возр", "Убыв", "Возр");
    Иначе
        ТекущаяКолонка = ИмяКолонки;
        Направление = "Возр";
    КонецЕсли;
    Дерево.Сортировать(ИмяКолонки + " " + Направление);
КонецПроцедуры

Альтернативы: сортировка через запрос и при построении

Если дерево строится из результата запроса с обходом по иерархии, часто проще отсортировать данные ещё на этапе запроса через УПОРЯДОЧИТЬ ПО с указанием ИЕРАРХИЯ для иерархических справочников. Тогда дерево сразу формируется в нужном порядке, и повторная сортировка в памяти не требуется.

ВЫБРАТЬ

Номенклатура.Ссылка КАК Ссылка,

Номенклатура.Наименование КАК Наименование

ИЗ

Справочник.Номенклатура КАК Номенклатура

УПОРЯДОЧИТЬ ПО

Наименование ИЕРАРХИЯ

Выбор между подходами зависит от источника данных: если дерево собирается из нескольких источников или динамически пересортировывается пользователем — метод Сортировать() удобнее. Если порядок фиксирован и данные берутся одним запросом — сортировка в запросе эффективнее, особенно на больших объёмах.

Сравнение подходов

Метод Сортировать()

Гибкая сортировка в памяти по любым колонкам и уровням; подходит для интерактивной пересортировки, но требует обхода данных в коде.

УПОРЯДОЧИТЬ ПО в запросе

Сортировка на стороне СУБД при выборке; быстрее на больших данных, но порядок фиксируется при построении дерева.

Сортировка коллекции строк узла

Точечная сортировка одного уровня; подходит, когда разные уровни требуют разного порядка.

Типичные ошибки и ограничения

Самая частая ошибка — ожидание, что Сортировать() у дерева отсортирует только верхний уровень. По умолчанию метод работает рекурсивно по всем уровням, и если вложенные строки должны были остаться в исходном порядке, они будут переставлены. Передавайте второй параметр явно.

Вторая группа проблем связана с типами данных: сортировка чисел, хранящихся как строки, даст порядок «1, 10, 2, 20». Также ошибкой является попытка отсортировать дерево по колонке, которой нет в коллекции, — это приводит к исключению в момент выполнения.

Типичные ошибки
01
Сортировка всего дерева вместо одного уровня — ломается задуманный порядок вложенных строк; передавайте второй параметр Ложь.
02
Числа в строковой колонке — получается лексикографический порядок вместо числового; задавайте правильный тип колонки при создании.
03
Пересоздание дерева вместо сортировки — теряется развёрнутость узлов на форме и выбранная строка.
04
Опечатка в имени колонки в строке параметров — ошибка исполнения, которую компилятор не проверит заранее.

Ограничение метода: нельзя задать собственный алгоритм сравнения (компаратор), как в некоторых других языках. Если нужна нестандартная логика — например, сортировка по вычисляемому признаку — добавьте служебную колонку, заполните её нужными значениями и сортируйте по ней.

Контрольные точки

Как проверить результат

Порядок строк верхнего уровня
Норма

Строки упорядочены по заданной колонке и направлению

Тревожный признак

Порядок не изменился или частичный — проверьте имя колонки и модификатор Возр/Убыв

Подчинённые строки
Норма

Дочерние строки переместились вместе с родителем, связи сохранены

Тревожный признак

Дочерние строки «отвалились» — вероятно, дерево пересоздавалось, а не сортировалось

Вложенные уровни
Норма

Каждый уровень отсортирован согласно параметру СортироватьПоИерархии

Тревожный признак

Уровни отсортированы, хотя не должны были — не передан второй параметр Ложь

Итог

Что важно запомнить

Метод Сортировать() по умолчанию обходит все уровни дерева, перемещая строки вместе с подчинёнными ветками. Для точечной сортировки вызывайте метод у коллекции строк нужного узла, следите за типами данных в колонках и при возможности сортируйте данные на этапе запроса.

Частые вопросы

Как отсортировать только верхний уровень дерева значений?

Вызовите метод у коллекции строк с параметром Ложь: Дерево.Строки.Сортировать("Наименование", Ложь). Вложенные уровни сохранят исходный порядок.

Можно ли сортировать дерево по колонке с разными типами данных?

Технически метод выполнится, но порядок может быть непредсказуемым, так как значения разных типов сравниваются по внутренним правилам платформы. Надёжнее заранее привести колонку к одному типу через описание типов при её создании.

Почему после сортировки числа идут в порядке 1, 10, 2?

Колонка имеет строковый тип, и сравнение идёт посимвольно. Создайте колонку с числовым типом через Новый ОписаниеТипов("Число") или преобразуйте значения перед сортировкой.

Сохраняется ли развёрнутость узлов на форме после сортировки?

Да, если вы сортируете существующее дерево методом Сортировать() — строки остаются теми же объектами, и состояние развёрнутости обычно сохраняется. Если дерево очищается и заполняется заново, развёрнутость теряется, и её нужно восстанавливать программно.

Что быстрее: сортировка методом Сортировать() или в запросе?

На больших объёмах данных сортировка в запросе через УПОРЯДОЧИТЬ ПО обычно эффективнее, так как выполняется на стороне СУБД. Метод Сортировать() удобен для интерактивной пересортировки уже загруженного дерева.

Как отсортировать дерево по собственному нестандартному правилу?

Встроенный метод не поддерживает пользовательский компаратор. Добавьте служебную колонку, заполните её значениями, отражающими нужный порядок (например, порядковыми номерами), и отсортируйте дерево по этой колонке.