Разработка и Конфигурация · 8 мин
Двумерный массив в 1С: как создать и работать с ним
В 1С нет встроенного двумерного массива. Разбираем рабочие способы: массив массивов, таблица значений, соответствие — с примерами кода и типичными ошибками.
Во встроенном языке 1С нет отдельного типа «двумерный массив» — объект Массив всегда одномерный. Однако задачи вроде матрицы остатков по складам, таблицы соответствий или шахматной доски значений решаются штатными средствами: массивом массивов, таблицей значений или соответствием с составным ключом.
Выбор подхода зависит от того, как вы будете обращаться к данным: по числовым индексам строки и колонки, по именованным колонкам или по произвольному ключу. Ниже разобраны все три варианта с готовым кодом, который можно перенести в модуль и сразу проверить.
Массив массивов: классическая замена двумерного массива
Самый близкий аналог двумерного массива — массив, каждый элемент которого сам является массивом. Внешний массив хранит строки, внутренние — значения в колонках. Обращение к ячейке выглядит привычно: Матрица[ИндексСтроки][ИндексКолонки].
Функция СоздатьМатрицу(КоличествоСтрок, КоличествоКолонок)
Матрица = Новый Массив;
Для ИндексСтроки = 0 По КоличествоСтрок - 1 Цикл
Строка = Новый Массив;
Для ИндексКолонки = 0 По КоличествоКолонок - 1 Цикл
Строка.Добавить(0); // начальное значение ячейки
КонецЦикла;
Матрица.Добавить(Строка);
КонецЦикла;
Возврат Матрица;
КонецФункции
Полученную матрицу заполняют и читают через двойную индексацию:
Матрица = СоздатьМатрицу(3, 4);
Матрица[1][2] = 150;
Сообщить(Матрица[1][2]); // 150
Важно помнить: индексация в 1С начинается с нуля, поэтому последняя строка матрицы из трёх строк имеет индекс 2. Обращение Матрица[3] вызовет ошибку «Индекс находится за границами массива».
Обход и проверка границ матрицы
Для перебора всех ячеек используйте вложенные циклы с методом ВГраница(), а не с жёстко заданными числами — так код переживёт изменение размеров:
Для ИндексСтроки = 0 По Матрица.ВГраница() Цикл
Строка = Матрица[ИндексСтроки];
Для ИндексКолонки = 0 По Строка.ВГраница() Цикл
Строка[ИндексКолонки] = ИндексСтроки * 10 + ИндексКолонки;
КонецЦикла;
КонецЦикла;
Если строки разной длины, вложенный цикл обязан опираться на границу именно текущей строки. Распространённая ошибка — использовать Матрица[0].ВГраница() для всех строк: при более короткой строке получите выход за границы, при более длинной — потеряете данные.
Таблица значений как структурированный двумерный массив
Когда данные имеют смысловые колонки — «Номенклатура», «Склад», «Количество» — вместо массива массивов правильнее использовать ТаблицаЗначений. Это фактически двумерная структура с именованными колонками, сортировкой, поиском и итогами из коробки.
Таблица = Новый ТаблицаЗначений;
Таблица.Колонки.Добавить("Склад");
Таблица.Колонки.Добавить("Товар");
Таблица.Колонки.Добавить("Количество", Новый ОписаниеТипов("Число"));
НоваяСтрока = Таблица.Добавить();
НоваяСтрока.Склад = "Основной";
НоваяСтрока.Товар = "Кабель";
НоваяСтрока.Количество = 120;
Доступ к ячейке возможен и по индексу: Таблица[0].Количество или Таблица[0]["Количество"]. Преимущества перед массивом массивов — методы Найти(), НайтиСтроки(), Сортировать(), Итог(), а также возможность передать таблицу в запрос как параметр или вывести в табличный документ.
Сравнение вариантов
Подходит для однотипных ячеек и доступа по числовым индексам; нет поиска и сортировки из коробки
Подходит для структурированных данных с именованными колонками; тяжелее по памяти, но даёт поиск, итоги и сортировку
Подходит для разреженных матриц и доступа по произвольному ключу; нет порядка строк и числовой индексации
Соответствие для разреженных данных
Если матрица большая, но заполнены лишь отдельные ячейки (например, цены только для части пар «поставщик–товар»), хранить полный массив расточительно. Используйте Соответствие, где ключ — структура или строка из пары индексов:
Ячейки = Новый Соответствие;
Ключ = "2_5"; // строка 2, колонка 5
Ячейки.Вставить(Ключ, 999);
Значение = Ячейки[Ключ];
Если Значение = Неопределено Тогда
// ячейка не заполнена
КонецЕсли;
Такой подход даёт мгновенный доступ по ключу и не требует выделять память под пустые ячейки. Минус — нельзя обойти «строку» целиком без дополнительного хранения списка ключей и нет гарантированного порядка элементов.
Как выбрать подходящий способ
Ориентируйтесь на сценарий использования, а не на привычку. Если вся логика строится на циклах по индексам и данные однотипны — массив массивов проще и легче. Если данные потом нужно искать, сортировать, сворачивать или показывать пользователю — сразу создавайте таблицу значений, иначе рефакторинг неизбежен.
Как выбрать действие
Отдельный случай — данные из запроса. Не перекладывайте выборку в массив массивов вручную: метод Выгрузить() результата запроса сразу возвращает таблицу значений, что и есть готовая двумерная структура.
Проверка результата и отладка
Быстрый способ убедиться, что матрица создана корректно, — вывести её размеры и контрольные значения:
Сообщить("Строк: " + Матрица.Количество());
Сообщить("Колонок в первой строке: " + Матрица[0].Количество());
Для Каждого Строка Из Матрица Цикл
Сообщить(СтрСоединить(Строка, " | "));
КонецЦикла;
В конфигураторе удобнее использовать отладчик: поставьте точку останова после заполнения и посмотрите структуру через «Вычислить выражение» (Shift+F9) — там видно вложенность массивов и содержимое каждой строки.
Как проверить результат
Количество() внешнего массива равно числу строк, каждая строка имеет нужную длину
Строк меньше ожидаемого или строки разной длины без причины
После Матрица[1][2] = X чтение возвращает X, соседние ячейки не изменились
Меняются сразу несколько строк — значит, добавлен один и тот же объект-строка
Цикл завершается без ошибок по ВГраница() каждой строки
Ошибка «Индекс за границами массива»
Что важно запомнить
Двумерного типа в 1С нет: используйте массив массивов для индексного доступа, таблицу значений для структурированных данных и соответствие для разреженных матриц. Индексация всегда с нуля, обход — только через ВГраница().
Частые вопросы
Можно ли объявить массив сразу с двумя измерениями, как Массив[10][10]?
Нет, конструктор Новый Массив принимает только размерность одномерного массива. Двумерность достигается добавлением массивов в элементы внешнего массива в цикле.
Почему при изменении одной ячейки меняются значения во всех строках?
Вы добавили в матрицу одну и ту же строку-объект несколько раз: массивы в 1С передаются по ссылке. Создавайте новую строку через Новый Массив внутри цикла на каждой итерации.
Что быстрее: массив массивов или таблица значений?
Для простого доступа по индексам массив массивов легче и быстрее. Но если нужны поиск, фильтрация или итоги, таблица значений выиграет за счёт встроенных механизмов — ручной перебор массива окажется медленнее и сложнее.
Как передать двумерный массив между клиентом и сервером?
Массивы и таблицы значений сериализуются платформой, поэтому их можно возвращать из серверных процедур в «толстом» и управляемом приложении. Учитывайте, что таблица значений на клиенте доступна не во всех режимах — часто её заменяют массивом структур.
Можно ли сделать трёхмерный массив?
Да, по тому же принципу: массив, содержащий массивы массивов. Обращение будет вида Данные[Слой][Строка][Колонка]. На практике при трёх и более измерениях удобнее использовать соответствие с составным ключом.
Как отсортировать массив массивов по значению колонки?
Штатной сортировки у массива массивов нет. Либо реализуйте алгоритм сортировки вручную, либо — что практичнее — перенесите данные в таблицу значений и вызовите метод Сортировать("Колонка Убыв").