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

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

Двумерный массив в 1С: как создать и работать с ним

В 1С нет встроенного двумерного массива. Разбираем рабочие способы: массив массивов, таблица значений, соответствие — с примерами кода и типичными ошибками.

Во встроенном языке 1С нет отдельного типа «двумерный массив» — объект Массив всегда одномерный. Однако задачи вроде матрицы остатков по складам, таблицы соответствий или шахматной доски значений решаются штатными средствами: массивом массивов, таблицей значений или соответствием с составным ключом.

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

Массив массивов: классическая замена двумерного массива

Самый близкий аналог двумерного массива — массив, каждый элемент которого сам является массивом. Внешний массив хранит строки, внутренние — значения в колонках. Обращение к ячейке выглядит привычно: Матрица[ИндексСтроки][ИндексКолонки].

Функция СоздатьМатрицу(КоличествоСтрок, КоличествоКолонок)

Матрица = Новый Массив;

Для ИндексСтроки = 0 По КоличествоСтрок - 1 Цикл

Строка = Новый Массив;

Для ИндексКолонки = 0 По КоличествоКолонок - 1 Цикл

Строка.Добавить(0); // начальное значение ячейки

КонецЦикла;

Матрица.Добавить(Строка);

КонецЦикла;

Возврат Матрица;

КонецФункции

Полученную матрицу заполняют и читают через двойную индексацию:

Матрица = СоздатьМатрицу(3, 4);

Матрица[1][2] = 150;

Сообщить(Матрица[1][2]); // 150

Важно помнить: индексация в 1С начинается с нуля, поэтому последняя строка матрицы из трёх строк имеет индекс 2. Обращение Матрица[3] вызовет ошибку «Индекс находится за границами массива».

Обход и проверка границ матрицы

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

Для ИндексСтроки = 0 По Матрица.ВГраница() Цикл

Строка = Матрица[ИндексСтроки];

Для ИндексКолонки = 0 По Строка.ВГраница() Цикл

Строка[ИндексКолонки] = ИндексСтроки * 10 + ИндексКолонки;

КонецЦикла;

КонецЦикла;

Если строки разной длины, вложенный цикл обязан опираться на границу именно текущей строки. Распространённая ошибка — использовать Матрица[0].ВГраница() для всех строк: при более короткой строке получите выход за границы, при более длинной — потеряете данные.

Типичные ошибки
01
Обращение Матрица[Строка, Колонка] — в 1С такой синтаксис не поддерживается, нужно Матрица[Строка][Колонка]
02
Индексация с единицы по привычке из других систем — в 1С первый элемент имеет индекс 0
03
Использование границы первой строки для обхода всех строк — при разной длине строк это даёт ошибку или пропуск данных
04
Добавление одной и той же строки-объекта в массив несколько раз — все «строки» окажутся ссылками на один массив

Таблица значений как структурированный двумерный массив

Когда данные имеют смысловые колонки — «Номенклатура», «Склад», «Количество» — вместо массива массивов правильнее использовать ТаблицаЗначений. Это фактически двумерная структура с именованными колонками, сортировкой, поиском и итогами из коробки.

Таблица = Новый ТаблицаЗначений;

Таблица.Колонки.Добавить("Склад");

Таблица.Колонки.Добавить("Товар");

Таблица.Колонки.Добавить("Количество", Новый ОписаниеТипов("Число"));

НоваяСтрока = Таблица.Добавить();

НоваяСтрока.Склад = "Основной";

НоваяСтрока.Товар = "Кабель";

НоваяСтрока.Количество = 120;

Доступ к ячейке возможен и по индексу: Таблица[0].Количество или Таблица[0]["Количество"]. Преимущества перед массивом массивов — методы Найти(), НайтиСтроки(), Сортировать(), Итог(), а также возможность передать таблицу в запрос как параметр или вывести в табличный документ.

Сравнение вариантов

Массив массивов

Подходит для однотипных ячеек и доступа по числовым индексам; нет поиска и сортировки из коробки

Таблица значений

Подходит для структурированных данных с именованными колонками; тяжелее по памяти, но даёт поиск, итоги и сортировку

Соответствие с составным ключом

Подходит для разреженных матриц и доступа по произвольному ключу; нет порядка строк и числовой индексации

Соответствие для разреженных данных

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

Ячейки = Новый Соответствие;

Ключ = "2_5"; // строка 2, колонка 5

Ячейки.Вставить(Ключ, 999);

Значение = Ячейки[Ключ];

Если Значение = Неопределено Тогда

// ячейка не заполнена

КонецЕсли;

Такой подход даёт мгновенный доступ по ключу и не требует выделять память под пустые ячейки. Минус — нельзя обойти «строку» целиком без дополнительного хранения списка ключей и нет гарантированного порядка элементов.

Как выбрать подходящий способ

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

Маршрут решения

Как выбрать действие

Нужна простая матрица чисел с доступом по [Строка][Колонка]Создайте массив массивов через вложенные циклы
Нужны поиск, сортировка, итоги или вывод пользователюИспользуйте таблицу значений с типизированными колонками
Заполнена малая часть ячеек большой матрицыПримените соответствие с составным строковым ключом
Данные приходят из запросаРаботайте с результатом запроса или выгрузите его в таблицу значений, а не копируйте в массив

Отдельный случай — данные из запроса. Не перекладывайте выборку в массив массивов вручную: метод Выгрузить() результата запроса сразу возвращает таблицу значений, что и есть готовая двумерная структура.

Проверка результата и отладка

Быстрый способ убедиться, что матрица создана корректно, — вывести её размеры и контрольные значения:

Сообщить("Строк: " + Матрица.Количество());

Сообщить("Колонок в первой строке: " + Матрица[0].Количество());

Для Каждого Строка Из Матрица Цикл

Сообщить(СтрСоединить(Строка, " | "));

КонецЦикла;

В конфигураторе удобнее использовать отладчик: поставьте точку останова после заполнения и посмотрите структуру через «Вычислить выражение» (Shift+F9) — там видно вложенность массивов и содержимое каждой строки.

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

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

Размерность матрицы
Норма

Количество() внешнего массива равно числу строк, каждая строка имеет нужную длину

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

Строк меньше ожидаемого или строки разной длины без причины

Запись в ячейку
Норма

После Матрица[1][2] = X чтение возвращает X, соседние ячейки не изменились

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

Меняются сразу несколько строк — значит, добавлен один и тот же объект-строка

Обход в цикле
Норма

Цикл завершается без ошибок по ВГраница() каждой строки

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

Ошибка «Индекс за границами массива»

Итог

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

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

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

Можно ли объявить массив сразу с двумя измерениями, как Массив[10][10]?

Нет, конструктор Новый Массив принимает только размерность одномерного массива. Двумерность достигается добавлением массивов в элементы внешнего массива в цикле.

Почему при изменении одной ячейки меняются значения во всех строках?

Вы добавили в матрицу одну и ту же строку-объект несколько раз: массивы в 1С передаются по ссылке. Создавайте новую строку через Новый Массив внутри цикла на каждой итерации.

Что быстрее: массив массивов или таблица значений?

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

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

Массивы и таблицы значений сериализуются платформой, поэтому их можно возвращать из серверных процедур в «толстом» и управляемом приложении. Учитывайте, что таблица значений на клиенте доступна не во всех режимах — часто её заменяют массивом структур.

Можно ли сделать трёхмерный массив?

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

Как отсортировать массив массивов по значению колонки?

Штатной сортировки у массива массивов нет. Либо реализуйте алгоритм сортировки вручную, либо — что практичнее — перенесите данные в таблицу значений и вызовите метод Сортировать("Колонка Убыв").