При проектировании бизнес-логики в платформе «1С:Предприятие» разработчики регулярно сталкиваются с необходимостью упорядочивания данных. Сортировка списков, подготовка данных для вывода в отчетах или на формах — все это требует четкого понимания того, как ведут себя различные коллекции. Иногда среди программистов возникает сомнение: гарантирует ли обычный Массив сохранение того порядка элементов, в котором они были в него добавлены? Или же платформа может произвольно перемешать данные внутри него?
В этой статье мы подробно проанализируем реальный пример кода из конфигурации «1С:Документооборот», разберем по шагам механизм выгрузки данных из запроса в массив и детально изучим особенности сохранения порядка в ключевых коллекциях 1С: Массив, Структура и Соответствие. Также мы заглянем в будущее и посмотрим, как изменилось поведение этих объектов в новом технологическом стеке 1С:Элемент.
Рассмотрим ситуацию, которая вызвала оживленную дискуссию на форуме. Разработчик обратил внимание на следующий программный код, отвечающий за получение отсортированного списка виджетов:
// Сортировка виджетов по наименованию
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Виджеты.Ссылка
|ИЗ
| Справочник.Виджеты КАК Виджеты
|ГДЕ
| Виджеты.Ссылка В(&Виджеты)
|
|УПОРЯДОЧИТЬ ПО
| Виджеты.Наименование";
Запрос.УстановитьПараметр("Виджеты", ДоступныеВиджеты);
Возврат Запрос.Выполнить().Выгрузить().ВыгрузитьКолонку("Ссылка");
У автора кода возникло опасение: если конечным результатом работы функции является Массив (который возвращается методом ВыгрузитьКолонку()), не «растеряется» ли сортировка, заданная в запросе через предложение УПОРЯДОЧИТЬ ПО? Давайте разберем эту цепочку вызовов по шагам, чтобы выяснить истину.
Выполняемый код работает строго детерминировано. Давайте проанализируем каждый этап преобразования данных:
УПОРЯДОЧИТЬ ПО Виджеты.Наименование гарантирует, что СУБД вернет выборку, отсортированную по алфавиту. Порядок строк на этом этапе строго определен требованиями запроса.Выгрузить() переносит записи из результата запроса в объект типа ТаблицаЗначений. Строки добавляются в таблицу последовательно, одна за другой, строго в том порядке, в котором их вернула база данных. Каждая строка получает свой индекс — от 0 до N-1. Таблица значений гарантирует неизменность индексов строк, если с ней не производятся явные манипуляции (например, повторная сортировка или удаление строк).ВыгрузитьКолонку("Ссылка") осуществляет последовательный обход строк таблицы значений (от нулевого индекса до последнего) и копирует значения из указанной колонки в новый объект типа Массив.Поскольку Массив в платформе 1С представляет собой классический индексированный динамический список, он физически сохраняет элементы ровно в той последовательности, в которой они в него добавлялись. Никакого «скрытого» перестроения индексов или хэширования внутри массива не происходит. Таким образом, возвращаемый массив гарантированно сохранит сортировку по наименованию.
Часто мнительность разработчиков 1С связана с тем, что в других коллекциях платформы порядок элементов действительно ведет себя не столь очевидно. Сомнения в надежности массива обычно возникают из-за путаницы с такими объектами, как Структура и Соответствие. Давайте детально разберем их поведение.
Объект типа Структура предназначен для хранения пар «Ключ - Значение», где доступ к элементам осуществляется по имени ключа (свойства). Тем не менее, платформой поддерживается обход структуры с помощью цикла Для каждого ... Из .... И здесь кроется важный нюанс:
ФиксированнаяСтруктура, где порядок обхода в документации прямо назван неопределенным.Объект Соответствие (аналог HashMap в других языках программирования) ведет себя еще более непредсказуемо:
В отличие от структуры, элементы в соответствие добавляются с использованием механизма хэширования ключей. Порядок обхода коллекции через цикл Для каждого является недетерминированным (псевдослучайным). Он зависит от хэш-функции ключей и может меняться при обновлении платформы или при изменении состава элементов.
Интересен исторический курьез реализации Соответствия в веб-клиенте 1С. В веб-клиенте под капотом JavaScript долгое время использовалась упрощенная реализация соответствия в виде массива объектов. Из-за этого поиск работал медленнее, но побочным эффектом было временное сохранение порядка вставки элементов в браузере. Однако на сервере этот порядок сразу же нарушался. Это еще раз подтверждает правило: никогда не используйте Соответствие для хранения упорядоченных списков.
Технологии 1С развиваются, и в новом стеке (проект 1С:Элемент) разработчики полностью пересмотрели поведение базовых коллекций, сделав его более современным и предсказуемым:
Подводя итог, мы можем составить краткий свод правил, которыми следует руководствоваться при написании кода:
Массив, состоящий из Структур, либо Таблицу Значений с колонками «Ключ» и «Значение». Не полагайтесь на прямой обход одной лишь Структуры или Соответствия.Запрос.Выполнить().Выгрузить().ВыгрузитьКолонку("ИмяКолонки") является абсолютно корректным, безопасным и широко применяется в типовых решениях фирмы «1С» для получения отсортированных списков значений.