Хранение и обработка матриц во встроенном языке 1С
Содержание
Отдельного типа «Матрица» во встроенном языке 1С 8.3 нет — и это первое, что стоит принять, прежде чем искать его в синтакс-помощнике. Матрицу в 1С собирают из трёх готовых коллекций: вложенного массива, таблицы значений и соответствия. Какую выбрать — зависит от того, что вы с данными делаете: считаете, показываете пользователю или храните разреженную таблицу.
Ниже — три способа создать двумерную матрицу, базовые операции над ней (перебор, умножение, транспонирование) и ориентир, когда какой вариант быстрее. Весь код — на встроенном языке, запускается в модуле объекта, обработке или консоли запросов без дополнительных библиотек.
Есть ли в 1С отдельный тип для матрицы
Короткого ответа «создайте объект типа Матрица» не существует: такого класса в платформе нет. Если вы видели в чужом коде переменную Матрица, это просто имя — за ним стоит одна из обычных коллекций.
Для двумерной числовой таблицы в 1С подходят три структуры:
- 📐 Вложенный массив (
Массивмассивов) — быстрый и лёгкий, идеален для расчётов. - 📊 Таблица значений (
ТаблицаЗначений) — удобна, когда матрицу надо показать на форме или выгрузить. - 🗂️ Соответствие (
Соответствие) — для разреженных матриц, где заполнена небольшая доля ячеек.
Все три создаются оператором Новый и живут в оперативной памяти сеанса. Выбор между ними разберём в конце, а начнём с самого частого — вложенных массивов.
Матрица на вложенных массивах
Конструктор Массив принимает размеры сразу по нескольким измерениям. Запись Новый Массив(3, 3) создаёт матрицу 3×3, где каждый элемент верхнего массива — это вложенный массив из трёх ячеек. Все ячейки изначально получают значение Неопределено.
// Матрица 3×3 на вложенных массивах
Матрица = Новый Массив(3, 3);
Матрица[0][0] = 1; // строка 0, столбец 0
Матрица[1][2] = 5; // строка 1, столбец 2
Обращение идёт по двум индексам: первый — строка, второй — столбец. Нумерация с нуля. Чтобы узнать размеры, у любого массива есть методы Количество() (число элементов) и ВГраница() (индекс последнего, то есть количество минус один).
Полный перебор матрицы — двойной цикл: внешний по строкам, внутренний по столбцам.
Для НомерСтроки = 0 По Матрица.ВГраница() Цикл
СтрокаМатрицы = Матрица[НомерСтроки];
Для НомерСтолбца = 0 По СтрокаМатрицы.ВГраница() Цикл
Значение = СтрокаМатрицы[НомерСтолбца];
// ... обработка Значение
КонецЦикла;
КонецЦикла;
Если размеры матрицы заранее неизвестны и она растёт по ходу работы, создавайте пустой массив Новый Массив и добавляйте строки методом Добавить(), передавая туда готовый массив-строку. Так получается матрица с переменным числом строк.
Плюс вложенных массивов — минимум накладных расходов: это чистая память без служебных структур, поэтому арифметику гоняют именно на них.
Матрица через таблицу значений
Когда матрицу нужно вывести на форму, отсортировать по столбцу или выгрузить в табличный документ, удобнее ТаблицаЗначений. Столбцы таблицы играют роль столбцов матрицы, строки — роль строк.
ТЗ = Новый ТаблицаЗначений;
ТЗ.Колонки.Добавить("К0", Новый ОписаниеТипов("Число"));
ТЗ.Колонки.Добавить("К1", Новый ОписаниеТипов("Число"));
ТЗ.Колонки.Добавить("К2", Новый ОписаниеТипов("Число"));
// Добавляем три пустые строки
Для Сч = 1 По 3 Цикл
ТЗ.Добавить();
КонецЦикла;
ТЗ[0][0] = 10; // строка 0, столбец по индексу 0
ТЗ[1].К2 = 25; // строка 1, столбец по имени «К2»
К ячейке можно обратиться двумя путями: по индексу столбца (ТЗ[1][2]) или по его имени (ТЗ[1].К2). Имя удобнее, когда столбцы осмысленные — например, склады или месяцы.
Таблица значений тяжелее массива: она хранит описание колонок, контролирует типы и умеет многое из коробки (Свернуть, Сортировать, НайтиСтроки, ВыгрузитьКолонку). За это платят скоростью — на больших чисто числовых расчётах таблица заметно медленнее вложенного массива.
Описание типа колонки через ОписаниеТипов задавайте осознанно. Если оставить колонку без типа, 1С разрешит писать в неё что угодно, и потом сложно поймать, откуда в матрице взялась строка вместо числа.
Разреженная матрица через соответствие
Матрица 1000×1000 — это миллион ячеек. Если реально заполнена сотня-другая (например, матрица смежности графа или связи «товар — склад», где большинство пар не встречается), держать миллион элементов в памяти расточительно. Здесь выручает Соответствие: храним только непустые ячейки, а ключом служит пара координат.
Разреженная = Новый Соответствие;
// Ключ — строка вида «строка;столбец»
Разреженная.Вставить("2;7", 3.14);
Разреженная.Вставить("0;5", 100);
// Чтение ячейки
Значение = Разреженная.Получить("2;7");
Если Значение = Неопределено Тогда
Значение = 0; // незаполненная ячейка считается нулём
КонецЕсли;
Склейка координат в строку "строка;столбец" — самый простой и надёжный ключ. Метод Получить() возвращает Неопределено для ячеек, которых нет, — это и есть «нули» разреженной матрицы, их не нужно хранить явно.
Перебирать такую матрицу можно только по заполненным ячейкам — циклом Для Каждого:
Для Каждого Ячейка Из Разреженная Цикл
Координаты = СтрРазделить(Ячейка.Ключ, ";"); // ["2", "7"]
Значение = Ячейка.Значение;
КонецЦикла;
Операции над матрицами: перебор, умножение, транспонирование
Арифметику матриц платформа не делает за вас — её пишут обычными циклами. Разберём две операции, в которых чаще всего ошибаются: умножение и транспонирование. Поэлементные сумма и разность устроены проще (складываем ячейки с одинаковыми индексами), поэтому отдельно их не расписываю.
Умножение матриц. Матрицу A размера н×м можно умножить на B размера м×п — результат будет н×п. Каждая ячейка результата — сумма произведений строки A на столбец B.
// A(н×м) * B(м×п) = C(н×п)
Функция УмножитьМатрицы(А, Б)
Н = А.Количество(); // строк в A
М = Б.Количество(); // строк в B (= столбцов в A)
П = Б[0].Количество(); // столбцов в B
Результат = Новый Массив(Н, П);
Для i = 0 По Н - 1 Цикл
Для j = 0 По П - 1 Цикл
Сумма = 0;
Для k = 0 По М - 1 Цикл
Сумма = Сумма + А[i][k] * Б[k][j];
КонецЦикла;
Результат[i][j] = Сумма;
КонецЦикла;
КонецЦикла;
Возврат Результат;
КонецФункции
Перед умножением проверяйте согласованность размеров: число столбцов A должно равняться числу строк B. Иначе обращение Б[k][j] вылетит за границу массива и вызовет ошибку выполнения.
Транспонирование — поворот матрицы: строки становятся столбцами. Ячейка [i][j] исходной матрицы переходит в [j][i] результата.
Функция Транспонировать(Матрица)
Строк = Матрица.Количество();
Столбцов = Матрица[0].Количество();
Результат = Новый Массив(Столбцов, Строк);
Для i = 0 По Строк - 1 Цикл
Для j = 0 По Столбцов - 1 Цикл
Результат[j][i] = Матрица[i][j];
КонецЦикла;
КонецЦикла;
Возврат Результат;
КонецФункции
Обе функции работают с вложенными массивами. Если матрица лежит в таблице значений, логика та же, меняется только синтаксис обращения к ячейке.
Что выбрать под размер и задачу
Три структуры — три профиля применения. Короткий ориентир по скорости: на плотных числовых расчётах вложенный массив работает заметно быстрее таблицы значений, потому что не тратит время на контроль типов и служебные поля. Таблица отыгрывает удобством, а соответствие — экономией памяти на разреженных данных.
| Способ | Когда брать | Слабое место |
|---|---|---|
| Вложенный массив | Плотная числовая матрица, важна скорость счёта | Нет готового вывода на форму |
| Таблица значений | Матрицу показывают пользователю или выгружают | Медленнее на чистой арифметике |
| Соответствие | Большая матрица, заполнена частично | Нет прямого доступа по [i][j] |
Новый Массив(Н, М) — минимум накладных расходов, прямой доступ по двум индексам.ВыгрузитьКолонку, Свернуть, сортировка.Новый Массив, в который строки добавляются методом Добавить().Где матрицы встречаются в прикладных задачах 1С
Чистая линейная алгебра в учётных конфигурациях нужна редко, а вот двумерные таблицы — постоянно. Под «матрицей» в прикладном коде обычно понимают именно их:
- 💰 Матрица цен — строки товары, столбцы склады или типы цен. Удобно собирать на таблице значений и выгружать в документ.
- 📦 Матрица «товар — склад» с остатками: часто разреженная (не каждый товар есть на каждом складе) — хорошая кандидатура для соответствия.
- 🧮 Распределение затрат по базам — таблица «статья затрат × подразделение» с коэффициентами.
- 🔗 Матрица смежности для графов (структура подчинённости, зависимости задач) — почти всегда разреженная.
- 📈 План-факт по месяцам — строки показатели, столбцы периоды; классическая матрица для отчёта.
Во всех этих случаях выбор структуры диктует не математика, а то, откуда данные берутся и куда уходят. Если матрица формируется запросом и тут же показывается — берите результат запроса как таблицу значений через Выгрузить(). Если считаете в памяти большой объём чисел — переносите в массивы.
Результат запроса Запрос.Выполнить().Выгрузить() сразу возвращает таблицу значений — её не нужно заполнять ячейка за ячейкой. Это самый быстрый способ получить матрицу из данных базы.
Частые вопросы
Чем матрица отличается от двумерного массива в 1С?
Можно ли запретить изменение готовой матрицы?
Новый ФиксированныйМассив(Массив). Такой массив доступен только на чтение, попытка записи вызовет ошибку. Защита действует на верхний уровень; вложенные массивы при необходимости фиксируйте отдельно.Как сохранить матрицу в реквизит или регистр?
ХранилищеЗначения: Новый ХранилищеЗначения(Матрица). Массивы и таблицы значений сериализуемы, поэтому матрицу можно положить в реквизит типа «Хранилище значения» и достать обратно методом Получить().Как передать матрицу с сервера на клиент?
Как обойти матрицу в обратном порядке?
Для i = Матрица.ВГраница() По 0 Шаг -1 Цикл. Для соответствия обратного перебора нет — выгрузите ключи в массив и переверните его.