Список двумерных массивов в 1С: возможно ли это и как правильно реализовать?

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

При разработке сложных алгоритмов в среде "1С:Предприятие" мы регулярно сталкиваемся с необходимостью организации сложных структур данных. Стандартных механизмов, таких как линейные массивы или плоские таблицы значений, не всегда достаточно для реализации заложенной бизнес-логики. Возникает закономерный вопрос: позволяет ли функционал платформы 1С хранить многомерные структуры (например, двумерные массивы) внутри других универсальных коллекций, в частности, в объекте СписокЗначений?

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

Разбор базового примера: работа над ошибками

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

Вот как выглядела первоначальная некорректная инициализация:


СписокМасивов = Новый СписокЗначений; // Опечатка в имени переменной
Масс = Новый Массив(3);
ДвуМасс = Новый Массив;
ДвуМасс.Добавить(Масс);
СписокМасивов.Добавить("Имя", ДвуМасс); // Неверный порядок параметров метода Добавить()

Разберем, почему этот код не будет работать в реальной базе 1С:

  1. Опечатка в переменной: Инициализация выполнена в переменную СписокМасивов (с одной буквой "с"), что в дальнейшем привело бы к ошибке обращения к неопределенной переменной при строгом синтаксическом контроле.
  2. Нарушение сигнатуры метода Добавить(): Метод Добавить() у объекта СписокЗначений принимает параметры в следующем порядке: Добавить(Значение, Представление, Пометка, Картинка). Автор же попытался первым параметром передать строковое представление ("Имя"), а вторым — сам объект коллекции (ДвуМасс). В результате в качестве значения элемента списка была бы записана строка, а не массив, что полностью разрушает исходную логику.

Давайте посмотрим на исправленный, полностью работоспособный вариант кода, который успешно пройдет синтаксический контроль платформы:


СписокМассивов = Новый СписокЗначений;

// Создаем внутренний массив (строку нашей будущей матрицы)
Масс = Новый Массив(3);
Масс[0] = "Значение 1";
Масс[1] = "Значение 2";
Масс[2] = "Значение 3";

// Создаем внешний массив (ступенчатый двумерный массив)
ДвуМасс = Новый Массив;
ДвуМасс.Добавить(Масс);

// Правильно добавляем полученную структуру в СписокЗначений
// Первый параметр - объект (ДвуМасс), второй - его строковое представление ("Имя")
СписокМассивов.Добавить(ДвуМасс, "Имя");

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

Разница между «массивом массивов» и «истинным» многомерным массивом

При проектировании многомерных матриц в 1С важно понимать разницу между двумя принципиально отличающимися подходами к их созданию. Разработчики часто путают ступенчатые (зубчатые) массивы и истинные многомерные массивы.

Вариант 1. Ступенчатый массив (Массив массивов)

Это подход, продемонстрированный в примере выше. Мы создаем одномерный массив, элементами которого вручную назначаем другие одномерные массивы. Главное преимущество такого метода — гибкость. "Строки" нашей таблицы могут иметь совершенно разную длину:


ЗубчатыйМассив = Новый Массив;

Строка1 = Новый Массив(2); // Длина - 2 элемента
Строка2 = Новый Массив(5); // Длина - 5 элементов

ЗубчатыйМассив.Добавить(Строка1);
ЗубчатыйМассив.Добавить(Строка2);

Вариант 2. Истинный многомерный массив

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


// Создаем прямоугольную матрицу: 3 строки и 5 колонок
ДвумерныйМассив = Новый Массив(3, 5);

При такой инициализации платформа автоматически заполнит все ячейки значением Неопределено. Обращение к элементам такой матрицы происходит с использованием последовательных квадратных скобок:


// Записываем значение в ячейку на пересечении 1-й строки и 5-й колонки (индексация с нуля)
ДвумерныйМассив[0][4] = "Целевое значение";

// Чтение значения из матрицы
ПолученноеЗначение = ДвумерныйМассив[0][4];

Оба этих варианта могут быть без ограничений помещены в СписокЗначений в качестве значения его элементов.

Сложные вложенные структуры данных

Платформа 1С позволяет конструировать невероятно сложные иерархические структуры. Нам никто не мешает создать коллекцию вида: "Массив Таблиц значений, в строках которых хранятся массивы структур". Это абсолютно легальный код с точки зрения компилятора 1С.

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


// Инициализируем корневой массив
КорневойМассив = Новый Массив;

// Создаем Таблицу значений
ТаблицаДанных = Новый ТаблицаЗначений;
ТаблицаДанных.Колонки.Добавить("Идентификатор", Новый ОписаниеТипов("Число"));
ТаблицаДанных.Колонки.Добавить("КоллекцияЭлементов", Новый ОписаниеТипов("Массив"));

// Заполняем строку таблицы
НоваяСтрока = ТаблицаДанных.Добавить();
НоваяСтрока.Идентификатор = 101;

// Создаем вложенный массив для строки таблицы
ВнутреннийМассив = Новый Массив;
ВнутреннийМассив.Добавить("Значение_А");
ВнутреннийМассив.Добавить("Значение_Б");

НоваяСтрока.КоллекцияЭлементов = ВнутреннийМассив;

// Помещаем таблицу значений внутрь корневого массива
КорневойМассив.Добавить(ТаблицаДанных);

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

Критически важные ограничения: Тонкий клиент против Сервера

Главная опасность при работе со сложными вложенными коллекциями в 1С кроется в понятии мутабельности и доступности типов данных на разных контекстах выполнения. Разберем эту ситуацию подробнее.

Такие типы данных, как Массив, Структура, Соответствие и СписокЗначений, относятся к универсальным коллекциям общего назначения. Они доступны как на стороне сервера, так и на тонком или веб-клиенте. Вы можете свободно передавать массив, содержащий внутри себя другие массивы и структуры, из серверной функции на клиент.

Однако объект ТаблицаЗначений (а также ДеревоЗначений) является строго серверным типом данных. Тонкий клиент "ничего не знает" о существовании таблицы значений. Если вы попытаетесь передать на тонкий клиент массив, внутри которого находится хотя бы одна таблица значений, система завершит работу аварийно, выдав ошибку: "Ошибка передачи мутабельного значения".

Как решить эту проблему?

Если перед нами стоит задача передать табличные структуры на сторону клиента внутри общего массива, мы должны предварительно выполнить их конвертацию в массив структур. Каждая структура в таком массиве будет эмулировать строку таблицы значений. Давайте рассмотрим готовый шаблон функции для такой конвертации:


&НаСервере
Функция КонвертироватьТаблицуВМассивСтруктур(ТаблицаДанных)
    
    Результат = Новый Массив;
    
    // Получаем массив имен колонок для быстрой сборки структур
    МассивКолонок = Новый Массив;
    Для Каждого Колонка Из ТаблицаДанных.Колонки Цикл
        МассивКолонок.Добавить(Колонка.Имя);
    КонецЦикла;
    
    // Переносим данные из таблицы значений в массив структур
    Для Каждого СтрокаТЗ Из ТаблицаДанных Цикл
        НоваяСтруктура = Новый Структура;
        Для Каждого ИмяКолонки Из МассивКолонок Цикл
            НоваяСтруктура.Вставить(ИмяКолонки, СтрокаТЗ[ИмяКолонки]);
        КонецЦикла;
        Результат.Добавить(НоваяСтруктура);
    КонецЦикла;
    
    Возврат Результат;
    
КонецФункции

Полученный в результате работы этой функции массив структур можно без каких-либо ограничений передавать на тонкий клиент и обходить в циклах на стороне интерфейса.

Нюансы сериализации сложных структур в JSON

В современной разработке интеграционных решений крайне популярна передача данных посредством формата JSON. Платформа 1С предоставляет мощный встроенный инструмент — объект ЗаписьJSON. Он без проблем справляется с автоматической сериализацией примитивных типов данных, массивов, структур и соответствий.

Однако если в вашей вложенной структуре, которую вы планируете упаковать в JSON, окажется СписокЗначений или ТаблицаЗначений, метод ЗаписатьJSON() завершится ошибкой, поскольку данные типы не поддерживаются спецификацией JSON напрямую.

Чтобы обойти это ограничение, нам необходимо использовать специальный параметр — функцию преобразования. Давайте разберем по шагам, как настроить сериализацию "сложного" массива, содержащего неподдерживаемые типы данных:


&НаСервере
Процедура СериализоватьСложнуюКоллекциюВJSON()
    
    // Подготовим данные со Списком значений внутри массива
    СложнаяСтруктура = Новый Массив;
    ВложенныйСписок = Новый СписокЗначений;
    ВложенныйСписок.Добавить("Элемент 1");
    ВложенныйСписок.Добавить("Элемент 2");
    
    СложнаяСтруктура.Добавить(ВложенныйСписок);
    
    // Настраиваем запись JSON
    Запись = Новый ЗаписьJSON;
    ПараметрыЗаписи = Новый ПараметрыЗаписиJSON(ПереносСтрокJSON.Авто, " ");
    Запись.УстановитьСтроку(ПараметрыЗаписи);
    
    // Вызываем запись с указанием обработчика нестандартных типов
    ЗаписатьJSON(Запись, СложнаяСтруктура, "МояФункцияПреобразования");
    
    СтрокаРезультат = Запись.Закрыть();
    Сообщить(СтрокаРезультат);
    
КонецПроцедуры

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

Использование функции преобразования позволяет гибко управлять выгрузкой любых нестандартных типов данных платформы 1С во внешние форматы обмена.

Взаимодействие с внешними системами: COMSafeArray

Бывают ситуации, когда многомерные массивы из 1С необходимо передать во внешние программные продукты через COM-технологию (например, при прямой выгрузке данных в листы Microsoft Excel или при вызове методов самописных библиотек, разработанных на C# или C++).

Напрямую передать объект типа Массив (и уж тем более массив массивов) во внешнюю среду не получится: сторонние системы не умеют работать с внутренними объектами типов 1С. Для решения этой проблемы в платформе предусмотрен специальный объект-обертка — COMSafeArray. Он преобразует коллекции 1С в совместимый формат SAFEARRAY, используемый в среде Windows.

Рассмотрим пример конструирования такого массива для передачи в COM-объект:


// Создаем двумерный безопасный массив строк: 2 строки и 3 колонки
// Тип данных VT_BSTR указывает на то, что массив будет хранить строки
ДвумерныйБезопасныйМассив = Новый COMSafeArray("VT_BSTR", 2, 3);

// Заполняем массив значениями
ДвумерныйБезопасныйМассив.SetValue(0, 0, "Строка1_Колонка1");
ДвумерныйБезопасныйМассив.SetValue(0, 1, "Строка1_Колонка2");
ДвумерныйБезопасныйМассив.SetValue(0, 2, "Строка1_Колонка3");

ДвумерныйБезопасныйМассив.SetValue(1, 0, "Строка2_Колонка1");
ДвумерныйБезопасныйМассив.SetValue(1, 1, "Строка2_Колонка2");
ДвумерныйБезопасныйМассив.SetValue(1, 2, "Строка2_Колонка3");

// Теперь этот объект можно передать как параметр в Excel или другую DLL
// Например: COMОбъектExcel.Range("A1:C2").Value = ДвумерныйБезопасныйМассив;

Использование COMSafeArray гарантирует корректную интерпретацию типов данных на стороне принимающего приложения и позволяет избежать труднодиагностируемых ошибок памяти при работе через COM-соединение.

Резюме

Платформа 1С предоставляет разработчику колоссальную свободу при работе с вложенными коллекциями. Мы можем хранить двумерные массивы (как ступенчатые, так и истинные многомерные) в списках значений, структурах и соответствиях. Однако при проектировании сложных систем всегда помните о правилах передачи данных между сервером и клиентом, а также о необходимости явной конвертации специфических серверных объектов перед их передачей или сериализацией.

← На главную