Хранение и обработка матриц во встроенном языке 1С

· 8 мин

Содержание

Отдельного типа «Матрица» во встроенном языке 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С?
Ничем по сути — это одно и то же. «Матрица» в 1С всегда реализуется как двумерная коллекция (вложенный массив, таблица значений или соответствие). Отдельного типа нет, слово используют только как название переменной.
Можно ли запретить изменение готовой матрицы?
Для массива — да, оберните его в Новый ФиксированныйМассив(Массив). Такой массив доступен только на чтение, попытка записи вызовет ошибку. Защита действует на верхний уровень; вложенные массивы при необходимости фиксируйте отдельно.
Как сохранить матрицу в реквизит или регистр?
Через ХранилищеЗначения: Новый ХранилищеЗначения(Матрица). Массивы и таблицы значений сериализуемы, поэтому матрицу можно положить в реквизит типа «Хранилище значения» и достать обратно методом Получить().
Как передать матрицу с сервера на клиент?
Вложенный массив и соответствие передаются между клиентом и сервером напрямую — они сериализуемы. Таблицу значений на управляемых формах между контекстами передавать нельзя: преобразуйте её в массив структур или держите в реквизите формы с типом «Таблица значений».
Как обойти матрицу в обратном порядке?
Идите по индексам от конца: Для i = Матрица.ВГраница() По 0 Шаг -1 Цикл. Для соответствия обратного перебора нет — выгрузите ключи в массив и переверните его.