Массив в 1С 8.3: создание, заполнение и методы работы

· 9 мин

Содержание

Пустой массив создаётся одной строкой: Массив = Новый Массив;. Если сразу известно, сколько элементов нужно, в конструктор передают число: Новый Массив(10) даёт массив на 10 элементов с индексами от 0 до 9. Добавляют значения методом Добавить, читают по индексу через квадратные скобки, перебирают циклом Для Каждого.

Массив во встроенном языке 1С 8.3 — это упорядоченный набор значений любого типа с доступом по числовому индексу. Нумерация всегда начинается с нуля. Ниже разберём, как объявить массив, заполнить его заранее известным размером, собрать фиксированный и многомерный массив, какие у него есть методы и почему он ведёт себя как ссылка, а не как значение.

Создание массива: конструктор Новый Массив

Базовая форма объявления — вызов конструктора без параметров. Так получается пустой массив, в который элементы добавляются по ходу работы:

Массив = Новый Массив;
Массив.Добавить("Яблоко");
Массив.Добавить("Груша");
Массив.Добавить(150);
Сообщить(Массив.Количество()); // 3

Обратите внимание: в одном массиве спокойно лежат и строки, и число. Типизация элементов свободная — язык не требует, чтобы весь набор был однородным.

Чтение значения — по индексу. Два способа равнозначны:

Первый = Массив[0];           // "Яблоко"
Второй = Массив.Получить(1);  // "Груша"

Запись в существующий элемент — так же, через скобки или метод Установить:

Массив[2] = 200;
Массив.Установить(0, "Слива");

Индекс последнего элемента всегда равен Количество() - 1. Попытка обратиться к Массив[Массив.Количество()] вызовет ошибку «Индекс находится за границами массива».

Массив заданного размера и его заполнение

Когда число элементов известно заранее, размер задают прямо в конструкторе. Все ячейки при этом получают значение Неопределено:

Дни = Новый Массив(7);
Сообщить(Дни[0]); // Неопределено

Такой массив удобно заполнять циклом по индексу. Верхнюю границу даёт метод ВГраница — он возвращает индекс последнего элемента (для пустого массива это −1):

Дни = Новый Массив(7);
Для Сч = 0 По Дни.ВГраница() Цикл
    Дни[Сч] = СтрШаблон("День %1", Сч + 1);
КонецЦикла;

Число и строку нельзя складывать напрямую: "День " + 1 приведёт к ошибке типа. Поэтому в примере используется СтрШаблон, который сам приводит число к строке. Альтернатива — явное преобразование: "День " + Строка(Сч + 1).

Разница между двумя способами объявления принципиальная:

КонструкторЧто получаемКогда применять
Новый МассивПустой, 0 элементовРазмер заранее не известен, элементы добавляем по мере обработки
Новый Массив(N)N ячеек со значением НеопределеноКоличество известно, индексы нужны сразу

Если заполнять заранее размеченный массив через Добавить, он вырастет за пределы N — метод всегда дописывает в конец, а не замещает пустые ячейки. Это частая причина лишних элементов Неопределено в начале.

Фиксированный массив: когда нужен неизменяемый список

ФиксированныйМассив — это массив, который нельзя менять после создания. Его собирают из обычного массива, передав тот в конструктор:

Исходный = Новый Массив;
Исходный.Добавить("Красный");
Исходный.Добавить("Зелёный");
Исходный.Добавить("Синий");

Цвета = Новый ФиксированныйМассив(Исходный);
Сообщить(Цвета.Количество()); // 3
Сообщить(Цвета[1]);           // "Зелёный"

Читать из фиксированного массива можно теми же способами — по индексу, через Получить, перебором в цикле, методом Найти. А вот Добавить, Удалить, Вставить и присваивание по индексу вызовут ошибку: набор защищён от изменения.

Зачем он нужен:

  • 🔒 Передача списка в процедуру, где он не должен случайно измениться.
  • 📌 Константные перечни — например, набор допустимых статусов или кодов.
  • ♻️ Параметры, которые по смыслу настраиваются один раз.

После упаковки в фиксированный массив связь с исходным теряется: изменения в Исходный на Цвета уже не влияют.

Чтобы снова получить изменяемую версию, соберите из фиксированного обычный массив перебором:

Изменяемый = Новый Массив;
Для Каждого Элемент Из Цвета Цикл
    Изменяемый.Добавить(Элемент);
КонецЦикла;

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

Многомерные и вложенные массивы

Многомерный массив получают, передав в конструктор несколько размеров через запятую. Запись Новый Массив(3, 2) создаёт три элемента, каждый из которых сам является массивом из двух ячеек:

Матрица = Новый Массив(3, 2);
Матрица[0][0] = 1;
Матрица[0][1] = 2;
Матрица[1][0] = 3;
Сообщить(Матрица[0][1]); // 2

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

Таблица = Новый Массив;
Для НомерСтроки = 1 По 3 Цикл
    Строка = Новый Массив;
    Строка.Добавить("Код");
    Строка.Добавить("Наименование");
    Таблица.Добавить(Строка);
КонецЦикла;

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

Обходят двумерный массив вложенными циклами — внешний по строкам, внутренний по ячейкам строки:

Для Каждого Строка Из Матрица Цикл
    Для Каждого Ячейка Из Строка Цикл
        Сообщить(Ячейка);
    КонецЦикла;
КонецЦикла;

Такая конструкция не зависит от числа столбцов и работает даже с «рваными» массивами, где строки разной длины.

Если данные по смыслу табличные (строки с одинаковым набором колонок), чаще удобнее ТаблицаЗначений с именованными колонками, чем вложенный массив с числовыми индексами. Читать Строка.Количество понятнее, чем помнить, что [2] — это цена.

Как получить массив из строки или таблицы

Конструктор — не единственный путь. Готовый массив возвращают несколько штатных методов, и это самый частый способ получить его на практике.

Разбор строки. Метод СтрРазделить режет строку по разделителю и отдаёт массив строк:

Коды = СтрРазделить("10;20;30", ";");
Сообщить(Коды.Количество()); // 3
Сообщить(Коды[0]);           // "10" (строка, не число)

Элементы здесь — строки, поэтому перед арифметикой их приводят к числу через Число(). Третий параметр СтрРазделить управляет тем, включать ли пустые подстроки.

Колонка таблицы значений. Метод ВыгрузитьКолонку собирает значения одной колонки в массив:

МассивАртикулов = ТаблицаТоваров.ВыгрузитьКолонку("Артикул");

Результат запроса. Та же пара методов работает после запроса: сначала результат выгружают в таблицу, затем берут из неё колонку:

Выборка = Запрос.Выполнить().Выгрузить();
МассивСсылок = Выборка.ВыгрузитьКолонку("Номенклатура");

Так получается массив ссылок, который удобно передать в параметр другого запроса (Номенклатура В (&МассивСсылок)) или в отбор формы. Это основной приём, когда массив нужен не сам по себе, а как набор отобранных данных.

Методы массива: добавить, найти, удалить, перебрать

Полный набор операций над элементами компактен. Вот основные методы:

  • ➕ Добавить(Значение) — дописать в конец.
  • ⤵️ Вставить(Индекс, Значение) — вставить на позицию, сдвинув остальные вправо.
  • ➖ Удалить(Индекс) — убрать элемент по индексу.
  • 🔍 Найти(Значение) — вернуть индекс первого совпадения или Неопределено, если значения нет.
  • 🔢 Количество() — число элементов.
  • 📏 ВГраница() — индекс последнего элемента (−1 для пустого).
  • 🧹 Очистить() — удалить все элементы.

Поиск удобно сочетать с проверкой на Неопределено:

Индекс = Массив.Найти("Груша");
Если Индекс <> Неопределено Тогда
    Массив.Удалить(Индекс);
КонецЕсли;

Вставка в середину сдвигает все последующие элементы вправо, поэтому индексы после точки вставки меняются:

Массив = Новый Массив;
Массив.Добавить("А");
Массив.Добавить("В");
Массив.Вставить(1, "Б"); // теперь ["А", "Б", "В"]

Перебрать массив можно двумя циклами. Когда индекс не важен — коротким Для Каждого:

Для Каждого Элемент Из Массив Цикл
    Сообщить(Элемент);
КонецЦикла;

Когда нужен именно номер элемента — циклом по индексу от 0 до ВГраница.

Отдельный случай — удаление элементов во время обхода. Менять массив внутри Для Каждого нельзя: возникнет ошибка «Запрещено изменение коллекции во время обхода». Удаляют с конца обычным циклом, чтобы индексы оставшихся элементов не смещались:

Сч = Массив.ВГраница();
Пока Сч >= 0 Цикл
    Если Массив[Сч] = Неопределено Тогда
        Массив.Удалить(Сч);
    КонецЕсли;
    Сч = Сч - 1;
КонецЦикла;

Проход от конца к началу важен: если удалять с нулевого элемента вперёд, после каждого Удалить оставшиеся сдвигаются, и часть элементов цикл пропустит.

Типизация, ссылки и производительность

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

Массив — ссылочный тип. Присваивание не копирует данные, а передаёт ссылку на тот же набор:

А = Новый Массив;
А.Добавить(1);
Б = А;          // Б и А указывают на один и тот же массив
Б.Добавить(2);
Сообщить(А.Количество()); // 2, не 1

То же касается передачи массива в процедуру: изменения внутри неё видны снаружи. Если нужна независимая копия — соберите новый массив перебором элементов исходного. Учтите: такой перебор копирует только верхний уровень. Если в ячейках лежат вложенные массивы или структуры, копии разделят с оригиналом те же вложенные объекты, и для полной независимости их придётся копировать отдельно.

Производительность зависит от операции. Полезно держать в голове порядок стоимости:

ОперацияСтоимостьКомментарий
ДобавитьДёшевоДописывание в конец
Доступ по индексу [i]ДёшевоПрямой адрес
Вставить / Удалить в серединеДорого на больших массивахСдвигает все последующие элементы
НайтиЛинейный переборЧем длиннее массив, тем дольше

Если по коллекции нужен частый поиск по ключу, а не по индексу, массив — не лучший выбор. Для этого есть Соответствие, где значение достаётся сразу по ключу:

Цены = Новый Соответствие;
Цены.Вставить("Яблоко", 150);
Цены.Вставить("Груша", 200);
Сообщить(Цены["Груша"]); // 200, без перебора

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

Типичные ошибки при работе с массивом

Ошибки здесь повторяются из версии в версию и легко диагностируются по тексту сообщения:

  • 🚫 «Индекс находится за границами массива» — обращение к несуществующему элементу. Чаще всего это [Количество()] вместо [Количество() - 1] или чтение из пустого массива.
  • 🚫 «Запрещено изменение коллекции во время обхода» — вызов Удалить, Добавить или Очистить внутри Для Каждого. Лечится обычным циклом с конца.
  • 🚫 Молчаливое изменение «чужого» массива — следствие ссылочной природы: передали массив в функцию, та его изменила. Если это нежелательно, передавайте копию.
  • 🚫 Попытка изменить ФиксированныйМассив — любой из методов записи вызовет ошибку. Создайте из него обычный массив.
Проверьте себя
Что вернёт `ВГраница()` для только что созданного `Новый Массив`?
Как правильно удалить несколько элементов массива в цикле?
Сколько элементов создаст `Новый Массив(5)`?

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

Чем массив отличается от соответствия и таблицы значений?
Массив — набор с доступом по числовому индексу и сохранённым порядком. Соответствие хранит пары «ключ — значение» и быстро ищет по ключу. ТаблицаЗначений — набор строк с именованными колонками. Для последовательной обработки берите массив, для поиска по ключу — соответствие, для табличных данных — таблицу значений.
Как отсортировать массив?
У самого массива метода сортировки нет. Значения перекладывают в СписокЗначений или ТаблицуЗначений и вызывают их штатную сортировку, после чего при необходимости собирают результат обратно в массив.
Как скопировать массив, чтобы оригинал не менялся?
Простое присваивание копию не создаёт — обе переменные ссылаются на один массив. Нужен новый массив, в который перебором добавлены элементы исходного. Для вложенных структур потребуется копировать и внутренние массивы.
Как проверить, что массив пустой?
Сравнить Массив.Количество() с нулём. Метод ВГраница() у пустого массива вернёт −1.
Можно ли хранить в одном массиве значения разных типов?
Да. Элементы не обязаны быть одного типа — в одном массиве допустимы строки, числа, ссылки на объекты, структуры и другие массивы.