Разработчики в среде «1С:Предприятие» регулярно сталкиваются с необходимостью конвертации данных из одной коллекции в другую. Особенно часто возникает задача взаимного преобразования между типом Массив и типом СписокЗначений. Кажется очевидным, что у обоих объектов должны быть симметричные методы для перевода данных «туда и обратно», однако на практике начинающие программисты часто не находят нужных функций и начинают писать громоздкие циклы перебора. В этой статье мы подробно разберем, как правильно, быстро и эффективно выполнять эти преобразования встроенными средствами платформы, почему разработчики платформы допустили архитектурную асимметрию и как использовать эти знания для оптимизации вашего кода.
Прежде чем перейти к коду, давайте ответим на вопрос: почему вообще возникает такая необходимость? Каждая коллекция в 1С имеет свое уникальное предназначение:
Из-за этих различий нам регулярно приходится конвертировать данные: например, мы получили массив значений из запроса, но хотим красиво показать его пользователю на форме с возможностью выбора (нужен список значений). Или наоборот: пользователь отметил галочками элементы в списке на форме, и теперь нам нужно передать эти «чистые» значения в запрос для проведения расчетов (нужен массив).
Давайте подробно разберем, как получить массив из списка значений. Для этого в платформе 1С предусмотрен штатный метод ВыгрузитьЗначения(), принадлежащий объекту СписокЗначений. Этот метод создает новый массив и автоматически копирует в него все значения из элементов списка.
Рассмотрим практический пример использования этого метода:
// Создадим и заполним тестовый список значений
СписокТоваров = Новый СписокЗначений;
СписокТоваров.Добавить(Справочники.Номенклатура.НайтиПоКоду("00000001"), "Товар 1");
СписокТоваров.Добавить(Справочники.Номенклатура.НайтиПоКоду("00000002"), "Товар 2");
// Преобразуем список значений в массив одной строкой кода
МассивТоваров = СписокТоваров.ВыгрузитьЗначения();
// Теперь в переменной МассивТоваров находится стандартный Массив
// Мы можем передать его, например, в параметры запроса
Важное примечание: при выгрузке значений из списка в массив полностью теряются сопутствующие метаданные элементов списка. Будут проигнорированы свойства Представление, Пометка и Картинка. В массив попадут исключительно «чистые» данные, содержащиеся в свойстве Значение каждого элемента списка.
Теперь рассмотрим обратную задачу: у нас есть массив, и нам нужно загрузить его элементы в список значений. Некоторые разработчики по ошибке ищут метод прямо у объекта Массив (например, ожидая увидеть что-то вроде ВыгрузитьВСписок()). Однако у массива таких методов нет. И это логично с точки зрения архитектуры: базовый и легкий тип данных не должен знать о существовании более тяжелых интерфейсных объектов.
Решение кроется в методе ЗагрузитьЗначения(), который принадлежит самому объекту СписокЗначений. Давайте посмотрим, как это выглядит на практике:
// Предположим, у нас есть исходный массив с какими-то данными
МассивИмен = Новый Массив;
МассивИмен.Добавить("Александр");
МассивИмен.Добавить("Мария");
МассивИмен.Добавить("Иван");
// Создаем новый список значений
СписокИмен = Новый СписокЗначений;
// Загружаем данные из массива в список
СписокИмен.ЗагрузитьЗначения(МассивИмен);
Что происходит «под капотом» платформы при вызове этого метода? Платформа автоматически обходит переданный массив, создает для каждого элемента объект типа ЭлементСпискаЗначений и заполняет его свойства по умолчанию:
Значение получает элемент из массива.Представление формируется автоматически как строковое представление значения.Пометка устанавливается в значение Ложь.Картинка остается пустым.Давайте проанализируем, почему разработчики платформы спроектировали эту связь именно так. Почему у списка значений есть оба метода (ЗагрузитьЗначения и ВыгрузитьЗначения), а у массива — ни одного?
В объектно-ориентированном программировании существует правило минимизации зависимостей. Массив — это системный, универсальный тип данных, который живет на всех уровнях платформы, включая самые глубокие серверные процессы и внешние соединения. Он должен оставаться максимально простым и производительным. СписокЗначений — это прикладной объект, тесно связанный с интерфейсом пользователя. Если бы мы добавили в Массив метод преобразования в СписокЗначений, нам пришлось бы связать базовый тип данных с интерфейсными библиотеками, что усложнило бы и утяжелило бы платформу.
Поэтому управление конвертацией полностью делегировано объекту СписокЗначений. Это красивое и логичное архитектурное решение.
Выяснив особенности работы этих методов, давайте рассмотрим очень популярный в сообществе 1С лайфхак. Дело в том, что стандартный объект Массив в 1С не имеет встроенного метода для сортировки элементов (в отличие от других языков программирования). Писать алгоритм сортировки (например, «пузырьком») самостоятельно на встроенном языке — это плохая практика, так как интерпретируемый код будет работать крайне медленно на больших объемах данных.
Решение этой проблемы элегантно реализуется через транзитную конвертацию данных в список значений, у которого метод сортировки есть:
// Наш неотсортированный массив чисел
МассивЧисел = Новый Массив;
МассивЧисел.Добавить(15);
МассивЧисел.Добавить(3);
МассивЧисел.Добавить(42);
МассивЧисел.Добавить(8);
// Шаг 1. Переносим данные в список значений
ТранзитныйСписок = Новый СписокЗначений;
ТранзитныйСписок.ЗагрузитьЗначения(МассивЧисел);
// Шаг 2. Сортируем список значений средствами платформы
ТранзитныйСписок.СортироватьПоЗначению(НаправлениеСортировки.Возр);
// Шаг 3. Выгружаем отсортированные данные обратно в массив
МассивЧисел = ТранзитныйСписок.ВыгрузитьЗначения();
// Теперь МассивЧисел содержит элементы: 3, 8, 15, 42
Почему это работает быстро? Сортировка внутри объекта СписокЗначений выполняется на уровне платформы, написанной на C++. Это происходит в десятки и сотни раз быстрее, чем аналогичные алгоритмы сортировки, написанные разработчиком вручную на встроенном языке 1С.
Иногда перед разработчиком стоит задача не просто отсортировать коллекцию, а выполнить более сложные манипуляции: многокритериальный поиск, группировку, типизацию или сортировку по нескольким колонкам. В таких ситуациях отличной альтернативой выступает ТаблицаЗначений.
У таблиц значений также есть встроенные оптимизированные методы для работы с массивами. Мы можем загружать данные в колонку таблицы и выгружать их обратно без использования циклов:
// Создаем таблицу значений с одной колонкой
Таблица = Новый ТаблицаЗначений;
Таблица.Колонки.Добавить("Имя", Новый ОписаниеТипов("Строка"));
// Загружаем массив прямо в колонку таблицы значений
МассивИмен = Новый Массив;
МассивИмен.Добавить("Анна");
МассивИмен.Добавить("Сергей");
Таблица.Колонки.Имя.ЗагрузитьКолонку(МассивИмен);
// Выгружаем колонку таблицы значений обратно в массив
НовыйМассив = Таблица.ВыгрузитьКолонку("Имя");
Этот способ незаменим, когда вам требуется промежуточная сложная аналитическая обработка данных на сервере.
Давайте сформулируем несколько важных правил по работе с коллекциями, которые уберегут вашу базу данных от падения производительности:
ЗагрузитьЗначения() и ВыгрузитьЗначения() вместо ручного обхода коллекций в цикле Для Каждого. Системные методы выполняются на уровне ядра платформы и экономят процессорное время.Массив — это очень легкий сериализуемый тип, а СписокЗначений нагружен метаданными интерфейса. Никогда не передавайте тяжелые списки значений с сервера на клиент без острой необходимости. Если вам нужно передать данные, выгрузите список значений в массив на сервере, передайте массив на клиент и там, если требуется, загрузите его обратно в локальный список значений.В (&Параметр) используйте именно массивы. Передача списков значений в запросы в старых версиях платформы могла вызывать ошибки, а в новых — просто создает лишнюю нагрузку на сериализацию данных. Предварительная выгрузка списка в массив перед установкой параметра запроса считается стандартом качественной разработки.Мы надеемся, что этот подробный разбор помог вам глубже понять механизмы взаимодействия массивов и списков значений в 1С. Применяйте штатные методы платформы, оптимизируйте свой код и пишите его лаконично!