Как создать и заполнить двумерный массив в 1С 8.3
Содержание
Двумерный массив в 1С — это массив, элементы которого сами являются массивами. Создать его можно одной строкой: Матрица = Новый Массив(3, 4);. Получите «таблицу» 3 на 4, где все ячейки равны Неопределено. Дальше остаётся заполнить её значениями и обойти в цикле.
Такая конструкция нужна, когда данные ложатся в сетку: матрица коэффициентов, остатки по складам и месяцам, результат разбора CSV, промежуточные расчёты в памяти. Когда колонок немного и типы фиксированы, двумерный массив работает быстрее и проще, чем таблица значений.
Ниже — объявление массива, заполнение вложенными циклами, запись по индексам, инициализация готовыми значениями и обход результата. Весь код — на встроенном языке 1С:Предприятие 8.3.
Что такое двумерный массив и как его объявить
Отдельного типа «двумерный массив» в 1С нет. Есть обычный Массив, в ячейки которого вы кладёте другие массивы. Объявить его можно двумя способами.
Способ первый — сразу заданного размера. Конструктор Новый Массив принимает несколько параметров, по одному на измерение:
// 3 строки по 4 столбца, все ячейки = Неопределено
Матрица = Новый Массив(3, 4);
Способ второй — наращивать динамически, когда число строк заранее неизвестно:
Матрица = Новый Массив;
Для Строка = 1 По 3 Цикл
СтрокаТаблицы = Новый Массив;
Матрица.Добавить(СтрокаТаблицы);
КонецЦикла;
Разница принципиальная. В первом случае вы получаете готовую сетку фиксированного размера — обращаетесь к любой ячейке по индексу. Во втором массив пустой, и каждую строку вы добавляете методом Добавить.
Если размерность известна заранее, выбирайте Новый Массив(n, m). Система выделит память сразу, и не придётся переставлять элементы при каждом добавлении.
Индексы в 1С начинаются с нуля. У массива из трёх строк индексы строк — 0, 1 и 2. Пустые ячейки по умолчанию хранят Неопределено, а не ноль.
Заполнение массива вложенными циклами
Основной способ заполнить двумерный массив — два вложенных цикла Для: внешний идёт по строкам, внутренний по столбцам. Границы берём не «на глаз», а через Количество(), чтобы код не ломался при смене размера:
ЧислоСтрок = 3;
ЧислоСтолбцов = 4;
Матрица = Новый Массив(ЧислоСтрок, ЧислоСтолбцов);
Для Стр = 0 По ЧислоСтрок - 1 Цикл
Для Стлб = 0 По ЧислоСтолбцов - 1 Цикл
Матрица[Стр][Стлб] = Стр * ЧислоСтолбцов + Стлб;
КонецЦикла;
КонецЦикла;
После такого прохода ячейка Матрица[0][0] равна 0, Матрица[0][1] — 1, а Матрица[2][3] — 11. Выражение Стр * ЧислоСтолбцов + Стлб даёт сквозную нумерацию, но вместо него подставьте любой свой расчёт: остаток со склада, сумму по месяцу, коэффициент.
Если массив вы создавали динамически (через Добавить), границы считайте от самих вложенных массивов:
Для Стр = 0 По Матрица.Количество() - 1 Цикл
СтрокаТаблицы = Матрица[Стр];
Для Стлб = 0 По СтрокаТаблицы.Количество() - 1 Цикл
СтрокаТаблицы[Стлб] = 0;
КонецЦикла;
КонецЦикла;
Такой вариант не привязан к жёстким числам и работает, даже если строки разной длины.
Чтение и запись значений по индексам
К конкретной ячейке обращаются двойным индексом: сначала номер строки, потом номер столбца.
Значение = Матрица[1][2]; // прочитать
Матрица[1][2] = 500; // записать
Запись Матрица[Стр][Стлб] = Значение работает только внутри уже существующих границ. Если строка создана как Новый Массив(4), в ней есть индексы 0–3. Обращение к Матрица[1][7] вызовет ошибку «Индекс находится за границами массива».
Перед записью по индексу убедитесь, что ячейка существует. Для массива фиксированного размера она создаётся сразу. Для динамического — только после Добавить. Выход за границу массива останавливает выполнение с ошибкой, поэтому индекс из внешнего источника всегда проверяйте.
Узнать число строк — Матрица.Количество(). Число столбцов в конкретной строке — Матрица[0].Количество(). Индекс последнего элемента отдаёт метод ВГраница():
ПоследняяСтрока = Матрица.ВГраница(); // равно Количество() - 1
ПоследнийСтолбец = Матрица[0].ВГраница();
Как задать массив готовыми значениями
Литералов вида [[1,2],[3,4]] в 1С нет. Готовые значения заносят через Добавить, собирая каждую строку отдельно:
Матрица = Новый Массив;
Строка1 = Новый Массив;
Строка1.Добавить("Яблоки");
Строка1.Добавить(50);
Матрица.Добавить(Строка1);
Строка2 = Новый Массив;
Строка2.Добавить("Груши");
Строка2.Добавить(80);
Матрица.Добавить(Строка2);
Обратите внимание: в одной строке лежат и строковое значение, и число. Массив не типизирован — в ячейках хранятся значения любых типов, вплоть до ссылок на справочники и других массивов.
Когда данные приходят из текста, строки удобно собирать разбором. Например, из набора строк «наименование;количество»:
Исходные = "Яблоки;50
Груши;80
Сливы;30";
Матрица = Новый Массив;
Для Каждого СтрокаТекста Из СтрРазделить(Исходные, Символы.ПС) Цикл
Матрица.Добавить(СтрРазделить(СтрокаТекста, ";"));
КонецЦикла;
СтрРазделить возвращает массив строк, поэтому каждая запись сразу становится строкой двумерного массива. Числа при необходимости приведите функцией Число().
Если нужно заполнить всю сетку одним значением (например, нулями перед подсчётом), это тоже делают вложенным циклом по индексам — отдельного «заполнить всё» у массива фиксированного размера нет, а по умолчанию в ячейках лежит Неопределено, которое в арифметике приведёт к ошибке.
Двумерный массив или таблица значений
Двумерный массив — не единственный способ хранить сетку. Для табличных данных часто удобнее ТаблицаЗначений: у неё именованные колонки с типами, сортировка, поиск и свёртка «из коробки».
| Критерий | Двумерный массив | Таблица значений |
|---|---|---|
| Доступ к ячейке | по номеру [стр][стлб] | по имени колонки Строка.Сумма |
| Типы колонок | любые, вперемешку | задаются при создании |
| Поиск, сортировка, итоги | вручную циклом | встроенные методы |
| Накладные расходы | минимальные | выше |
Вывод простой: массив берут для компактных числовых сеток и промежуточных расчётов, таблицу значений — когда у столбцов есть смысл (наименование, количество, сумма) и нужны готовые операции над данными.
Ещё один признак: если сетку нужно показать пользователю или выгрузить, почти всегда выигрывает таблица значений — её связывают с таблицей на форме и сортируют парой строк кода. Если же массив живёт внутри одного алгоритма и наружу не выходит, лишняя обвязка таблицы значений не нужна.
Большие объёмы: как не потерять в скорости
На сотнях и тысячах строк важно, как именно вы работаете с массивом.
- 🧱 Выделяйте память заранее.
Новый Массив(ЧислоСтрок, ЧислоСтолбцов)быстрее, чем наращиваниеДобавитьв цикле: системе не приходится многократно перестраивать внутреннюю структуру. - 🔎 Не ищите линейно в цикле. Метод
Найтипросматривает массив целиком. ВызовНайтивнутри вложенного цикла превращает алгоритм в перебор «каждый с каждым». Если по значению нужен быстрый доступ — заведитеСоответствие(ключ → строка) и обращайтесь к нему напрямую. - 📏 Выносите
Количество()из тела цикла, если размер не меняется: посчитайте один раз в переменную и используйте её как границу. - 🗂 Для типизированных данных берите таблицу значений. У неё есть
ВыгрузитьКолонку,Свернуть, индексы — это заметно экономит код и время на выборках.
Соответствие (Соответствие) — главный приём против «тормозов» на поиске. Один проход по массиву строит индекс, а дальше поиск любого значения идёт за одно обращение вместо полного перебора.
Память тоже стоит держать в уме: двумерный массив целиком лежит в оперативной памяти, поэтому сетку в миллионы ячеек правильнее обрабатывать порциями или переносить расчёт в запрос к базе.
Обход, вывод и преобразование результата
Готовый массив обходят либо по индексам, либо конструкцией Для Каждого. Второй вариант короче, когда индекс сам по себе не нужен:
Для Каждого СтрокаТаблицы Из Матрица Цикл
ТекстСтроки = "";
Для Каждого Значение Из СтрокаТаблицы Цикл
ТекстСтроки = ТекстСтроки + Формат(Значение, "ЧГ=0") + " | ";
КонецЦикла;
Сообщить(ТекстСтроки);
КонецЦикла;
Здесь число склеивается со строкой через Формат — без явного приведения 1С выдаст ошибку сложения разных типов. Для чисел с разделителями подойдёт Формат(Значение, "ЧДЦ=2"), для произвольных типов — СтрШаблон("%1", Значение).
Частая задача при обходе — не просто вывести, а свернуть данные: посчитать сумму по столбцу или итог по строке. Сумма значений одного столбца по всем строкам:
НомерСтолбца = 1;
Итог = 0;
Для Каждого СтрокаТаблицы Из Матрица Цикл
Значение = СтрокаТаблицы[НомерСтолбца];
Если ТипЗнч(Значение) = Тип("Число") Тогда
Итог = Итог + Значение;
КонецЕсли;
КонецЦикла;
Проверка ТипЗнч(Значение) = Тип("Число") защищает расчёт от Неопределено и текстовых ячеек — без неё первый же нечисловой элемент оборвёт сложение ошибкой. Для итога по строке проход нужен только по внутреннему массиву этой строки.
Чтобы показать результат пользователю в виде настоящей таблицы, выгрузите массив в ТабличныйДокумент:
Таблица = Новый ТабличныйДокумент;
Для Каждого СтрокаТаблицы Из Матрица Цикл
ОбластьСтроки = Таблица.ПолучитьОбласть();
// заполнение ячеек области значениями строки
Таблица.Вывести(ОбластьСтроки);
КонецЦикла;
Для дальнейшей обработки чаще преобразуют массив в ТаблицаЗначений: создают колонки и добавляют строки в цикле. После этого доступны сортировка, отбор и выгрузка результата — всё то, чего у голого массива нет.
Типичные ошибки при работе с массивом
Ошибки с двумерным массивом почти всегда сводятся к одному: не ту ячейку прочитали или вышли за границу. Разберём то, на чём спотыкаются чаще всего.
- 🔀 Перепутан порядок индексов. Договоритесь с собой раз и навсегда: первый индекс — строка, второй — столбец, то есть
Матрица[строка][столбец]. Если в одном месте пишете[строка][столбец], а в другом[столбец][строка], данные тихо «поедут», и ошибки не будет — будет неверный результат. - 1️⃣ Забыли, что индексы с нуля. Массив из трёх строк имеет индексы 0, 1, 2. Граница цикла —
По Количество() - 1, а неПо Количество(). Забытая единица даёт выход за границу на последнем шаге. - 🔁 Меняют массив прямо во время
Для Каждого. Добавление или удаление элементов внутри обходаДля Каждого … Из …приводит к ошибке. Если нужно удалять по условию, идите обратным циклом по индексам:Для Сч = Матрица.Количество() - 1 По 0 Циклс шагом вниз. - 🔗 Думают, что скопировали, а работают с оригиналом. Присваивание
Копия = Матрицане создаёт новый массив — обе переменные ссылаются на один объект. ПравкаКопия[0][0]изменит иМатрица. Для настоящей копии переберите элементы в новый массив. - 🔢 Ждут от
Количество()общее число ячеек. У массива, созданного какНовый Массив(3, 4), методКоличество()вернёт 3 — число строк верхнего уровня, а не 12. Общее число ячеек считайте как произведение размерностей.
Если в середине таблицы встречается Неопределено там, где ждёте число, проверьте: ячейку просто не заполнили в цикле. Пропущенный диапазон индексов — частая причина «дыр» в данных.
Частые вопросы
Передаётся ли массив в процедуру по значению или по ссылке?
Можно ли сделать строки разной длины?
Добавить, каждая вложенная строка может содержать своё число столбцов. Это нормальный «зубчатый» массив, но тогда границы считайте отдельно для каждой строки.Как получить размерность по каждому измерению?
Матрица.Количество(). Число столбцов в конкретной строке — Матрица[0].Количество(). Единого «размера матрицы», как в математике, у массива нет, поэтому длину строки берут у самой строки.Что делать, если в ячейке оказалось `Неопределено`?
Если Матрица[Стр][Стлб] = Неопределено Тогда — и подставляйте ноль или пропускайте.Чем трёхмерный массив отличается от двумерного?
Новый Массив(2, 3, 4) создаёт массив массивов массивов, а доступ идёт тремя индексами Матрица[i][j][k]. На практике глубже двух-трёх измерений переходят редко — читаемость падает.