Добавление элементов в массив на встроенном языке 1С 8.3

· 9 мин

Содержание

Чтобы добавить значение в массив 1С, вызовите метод Добавить(): Массив.Добавить(Значение) кладёт элемент в конец. Если нужно поставить элемент в конкретную позицию, используйте Вставить(Индекс, Значение), а чтобы заменить существующий — запишите по индексу: Массив[2] = Значение.

Этого хватает для 90% задач. Сложности начинаются, когда надо склеить два массива, не допустить дублей, заполнить массив из запроса или передать его в процедуру. Всё это — ниже, с кодом, который можно копировать в модуль. Синтаксис одинаков для всех конфигураций на платформе 8.3: БП, ЗУП, УТ, ERP, собственные разработки.

Как создать массив и добавить в него элемент методом Добавить()

Массив создаётся конструктором Новый Массив. Пустой массив — без параметров:

Товары = Новый Массив;
Товары.Добавить("Бумага А4");
Товары.Добавить("Скрепки");
Товары.Добавить(150);

// Товары.Количество() = 3
// Товары[0] = "Бумага А4", Товары[2] = 150

Что полезно знать про Добавить():

  • ➕ элемент всегда встаёт в конец, индекс нового элемента равен Количество() - 1;
  • 🔢 нумерация начинается с нуля: первый элемент — Массив[0];
  • 🧩 массив разнотипный: в одном массиве могут лежать строка, число, ссылка на справочник и даже другой массив;
  • ↩️ метод ничего не возвращает. Конструкция Элемент = Массив.Добавить(...) — ошибка, в отличие от СписокЗначений.

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

Если передать в конструктор число, получится массив из N элементов со значением Неопределено:

Месяцы = Новый Массив(12);
// Месяцы.Количество() = 12, все элементы = Неопределено

Месяцы[0] = "Январь";
Месяцы[11] = "Декабрь";

Такой массив заполняют записью по индексу, а не Добавить(). Если вызвать Месяцы.Добавить("Январь"), элемент станет тринадцатым, а двенадцать пустых останутся в начале. Это частая причина «лишних» Неопределено в выгрузках.

Заполнение в цикле

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

Суммы = Новый Массив;
Для Каждого СтрокаТЧ Из Объект.Товары Цикл
    Если СтрокаТЧ.Сумма > 0 Тогда
        Суммы.Добавить(СтрокаТЧ.Сумма);
    КонецЕсли;
КонецЦикла;

Если нужна просто колонка табличной части или таблицы значений целиком, цикл не нужен: Объект.Товары.ВыгрузитьКолонку("Номенклатура") сразу вернёт массив.

Вставка значения в нужную позицию: Вставить() и запись по индексу

Вставить(Индекс, Значение) раздвигает массив: элемент встаёт на указанное место, а все следующие сдвигаются на одну позицию вправо.

Очередь = Новый Массив;
Очередь.Добавить("Петров");   // [0]
Очередь.Добавить("Сидоров");  // [1]

Очередь.Вставить(0, "Иванов");
// Иванов [0], Петров [1], Сидоров [2]

Очередь.Вставить(Очередь.Количество(), "Козлов");
// то же, что Добавить: Козлов встаёт в конец [3]

Запись по индексу работает иначе — она заменяет значение, размер массива не меняется:

СпособЧто делаетРазмер массиваКогда брать
Добавить(Значение)кладёт в конец+1обычное накопление
Вставить(Индекс, Значение)вставляет со сдвигом+1порядок важен: сортированный список, приоритет
Массив[Индекс] = Значениезаменяет элементне меняетсяисправить или заполнить заранее созданный массив
Установить(Индекс, Значение)то же, что запись по индексуне меняетсяв коде, где удобнее вызов метода

Запись по индексу за пределами массива вызывает ошибку времени выполнения Индекс находится за границами диапазона. Для пустого массива недопустим даже Массив[0] = ...: элемента с индексом 0 ещё нет, сначала его нужно добавить.

Вставить() в начало большого массива медленнее, чем Добавить(): платформе приходится сдвигать все элементы. На десятках тысяч элементов в цикле это заметно. Если порядок нужен обратный, соберите массив через Добавить(), а потом читайте его с конца.

Объединение массивов: как добавить в массив значения из другого массива

У объекта Массив нет метода, который добавляет сразу другой массив. Вызов Массив1.Добавить(Массив2) не склеит их — он положит весь Массив2 одним элементом внутрь Массив1. Получится вложенный массив, и при обходе вы увидите в элементе не значение, а коллекцию.

Правильный способ на чистом встроенном языке — цикл:

Процедура ДополнитьМассив(Приемник, Источник)
    Для Каждого Элемент Из Источник Цикл
        Приемник.Добавить(Элемент);
    КонецЦикла;
КонецПроцедуры

Первый = Новый Массив;
Первый.Добавить(1);
Первый.Добавить(2);

Второй = Новый Массив;
Второй.Добавить(3);
Второй.Добавить(4);

ДополнитьМассив(Первый, Второй);
// Первый: 1, 2, 3, 4

Готовая функция из БСП

В типовых конфигурациях (БП 3.0, ЗУП 3.1, УТ 11, ERP и любых других на Библиотеке стандартных подсистем) писать цикл не нужно. В общем модуле ОбщегоНазначенияКлиентСервер есть процедура:

ОбщегоНазначенияКлиентСервер.ДополнитьМассив(Первый, Второй);

// третий параметр Истина — добавлять только значения,
// которых ещё нет в приемнике
ОбщегоНазначенияКлиентСервер.ДополнитьМассив(Первый, Второй, Истина);

Модуль клиент-серверный, поэтому вызов работает и в модуле формы на клиенте, и на сервере. В конфигурации без БСП этого модуля нет — используйте свою процедуру из примера выше.

Добавление без дублей: уникальные значения в массиве

Самый простой способ — проверять значение через Найти() перед добавлением. Метод возвращает индекс найденного элемента или Неопределено:

Если Склады.Найти(Склад) = Неопределено Тогда
    Склады.Добавить(Склад);
КонецЕсли;

Способ хорош для коротких массивов. Найти() перебирает элементы по порядку, поэтому на каждом добавлении время растёт. На массиве в 50–100 тысяч элементов цикл с такой проверкой заметно тормозит.

Для больших объёмов уникальность держат через Соответствие — поиск по ключу в нём быстрый:

Уже = Новый Соответствие;
Уникальные = Новый Массив;

Для Каждого Строка Из ТаблицаДанных Цикл
    Если Уже[Строка.Контрагент] = Неопределено Тогда
        Уже.Вставить(Строка.Контрагент, Истина);
        Уникальные.Добавить(Строка.Контрагент);
    КонецЕсли;
КонецЦикла;

Если массив с повторами уже собран, в БСП его сворачивает функция ОбщегоНазначенияКлиентСервер.СвернутьМассив(Массив) — она возвращает новый массив без дублей. А если данные приходят из запроса, проще сразу написать ВЫБРАТЬ РАЗЛИЧНЫЕ и выгрузить колонку результата.

Когда вместо массива удобнее СписокЗначений, Соответствие или Структура

Массив хранит только значения. Если к значению нужно приложить что-то ещё — подпись, пометку, ключ, — берите другую коллекцию. Добавление в них похоже, но методы и возвращаемые значения различаются.

КоллекцияКак добавитьЧто хранитТипичная задача
МассивДобавить(Значение)значения по индексупараметр запроса, список ссылок
СписокЗначенийДобавить(Значение, Представление, Пометка)значение + подпись + флажоквыбор пользователем, список выбора поля
СоответствиеВставить(Ключ, Значение)пары ключ — значениебыстрый поиск по ключу, кэш
СтруктураВставить("Имя", Значение)пары с ключом-строкойпараметры процедур, настройки

СписокЗначений

Список = Новый СписокЗначений;
Элемент = Список.Добавить(Справочники.Валюты.НайтиПоКоду("643"), "Рубль", Истина);
// метод возвращает ЭлементСпискаЗначений — с ним можно работать дальше

Между массивом и списком значения легко перекладываются: Список.ВыгрузитьЗначения() возвращает массив, Список.ЗагрузитьЗначения(Массив) заполняет список из массива.

Соответствие и Структура

У этих коллекций нет Добавить(), только Вставить(). Повторный Вставить() с тем же ключом не создаёт второй элемент, а перезаписывает значение. Это удобно для накопления итогов:

Итоги = Новый Соответствие;
Для Каждого СтрокаТЧ Из Объект.Товары Цикл
    Было = Итоги[СтрокаТЧ.Номенклатура];
    Итоги.Вставить(СтрокаТЧ.Номенклатура, ?(Было = Неопределено, 0, Было) + СтрокаТЧ.Сумма);
КонецЦикла;

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

Массив в реальном коде: запросы, строки, передача в процедуры

Массив как параметр запроса

Главное практическое применение массива — отбор в запросе по списку значений:

Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
|    Остатки.Номенклатура,
|    Остатки.КоличествоОстаток
|ИЗ
|    РегистрНакопления.ТоварыНаСкладах.Остатки(, Склад В (&Склады)) КАК Остатки";
Запрос.УстановитьПараметр("Склады", Склады);

Если массив пустой, условие В (&Склады) не отберёт ни одной строки. Перед выполнением проверяйте Склады.Количество() > 0, если пустой массив по смыслу означает «все склады».

Массив из строки и обратно

Строку с разделителями превращает в массив СтрРазделить(), обратно собирает СтрСоединить():

Коды = СтрРазделить("001;002;;003", ";", Ложь);
// Ложь — пустые части отбрасываются: 001, 002, 003

Коды.Добавить("004");
Строка = СтрСоединить(Коды, ", ");
// "001, 002, 003, 004"

Чтобы добавить в строку число, сначала приведите его к строке: Формат(Число, "ЧГ=0"), иначе 12500 превратится в «12 500» с неразрывным пробелом.

Передача массива в процедуру

Массив передаётся по ссылке. Процедура, которая вызывает Добавить() у параметра, меняет исходный массив вызывающего кода. Ключевое слово Знач здесь не спасает: оно запрещает подменить саму переменную, но содержимое массива всё равно общее.

Если исходник нужно сохранить нетронутым, работайте с копией. В БСП это ОбщегоНазначения.СкопироватьРекурсивно(Массив) (на сервере) или цикл с Добавить() в новый массив.

Фиксированный массив

ФиксированныйМассив нельзя изменить: у него нет Добавить() и Вставить(). Он встречается в параметрах сеанса, в данных форм и в возвращаемых значениях с повторным использованием. Чтобы дописать в него значение, создайте обычный массив на его основе:

Изменяемый = Новый Массив(ФиксированныйМассивНастроек);
Изменяемый.Добавить(НовоеЗначение);
ФиксированныйМассивНастроек = Новый ФиксированныйМассив(Изменяемый);

Что изменилось в работе с массивами на платформе 8.3

Сам объект Массив и его методы Добавить, Вставить, Установить, Найти, Удалить работают одинаково во всех релизах 8.3. Разница между версиями — во вспомогательных функциях вокруг массива:

  • 🧵 СтрРазделить() и СтрСоединить() появились в 8.3.6. На более ранних платформах строку резали циклом по СтрНайти() или через функцию БСП СтрРазложитьСтрокуВМассивПодстрок() из модуля СтроковыеФункцииКлиентСервер;
  • 🔤 там же, в 8.3.6, добавлены СтрШаблон() и СтрНайти(), которые удобны при сборке массива строк;
  • 📦 функции БСП ДополнитьМассив() и СвернутьМассив() есть во всех актуальных типовых конфигурациях; в старых самописных базах без БСП их нет.

Если код должен работать в базе с режимом совместимости ниже 8.3.6, новые строковые функции будут недоступны, хотя сама платформа новее. Режим совместимости смотрят в свойствах корня конфигурации в Конфигураторе.

Частые ошибки при добавлении элементов в массив

  • ❌ Склеивание через Добавить(ДругойМассив). Получается вложенный массив вместо объединения. Лечится циклом или ДополнитьМассив().
  • ❌ Добавить() в массив, созданный как Новый Массив(N). Новые значения уходят в хвост после N пустых элементов.
  • ❌ Изменение массива во время обхода Для Каждого. Не добавляйте и не удаляйте элементы в той же коллекции, которую перебираете: собирайте результат в отдельный массив.
  • ❌ Удаление в прямом цикле по индексу. После Удалить() элементы сдвигаются, и следующий пропускается. Удалять нужно с конца: Для Сч = 1 По Массив.Количество() Цикл Инд = Массив.Количество() - Сч; .... Граница цикла вычисляется один раз при входе, а индекс считается от текущего размера, поэтому так безопасно.
  • ❌ Ожидание, что Найти() сравнивает структуры. Две разные Структуры с одинаковыми полями для Найти() не равны: сравниваются ссылки на объекты, а не содержимое. Для поиска по полям ищите в цикле или храните данные в таблице значений.
  • ❌ Передача массива с клиента на сервер с несериализуемыми значениями. Массив передаётся в серверный вызов, но только если внутри лежат передаваемые типы. Объект ДокументОбъект или Запрос внутри массива вызовут ошибку — передавайте ссылки и примитивы.
Перед тем как добавлять в массив, проверьте
Выполнено: 0 / 5

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

Как узнать, сколько элементов в массиве?
Метод Количество(). Индекс последнего элемента возвращает ВГраница(), он равен Количество() - 1. У пустого массива ВГраница() равна -1.
Можно ли добавить в массив сразу несколько значений одной строкой?
Встроенного метода нет. Либо несколько вызовов Добавить(), либо СтрРазделить() для строковых значений, либо ДополнитьМассив() из БСП, если значения уже лежат в другом массиве.
Как сделать двумерный массив и добавлять в него строки?
Создайте массив, элементами которого будут другие массивы: соберите строку в Строка = Новый Массив, затем Таблица.Добавить(Строка). Обращение — Таблица[0][1]. Для данных с колонками удобнее ТаблицаЗначений.
Как отсортировать массив после добавления?
У массива нет метода сортировки. Переложите значения в СписокЗначений через ЗагрузитьЗначения(), вызовите СортироватьПоЗначению() и выгрузите обратно ВыгрузитьЗначения().
Есть ли ограничение на размер массива?
Жёсткого лимита на число элементов нет, упор идёт в память процесса. Массив на сотни тысяч ссылок нормально живёт на сервере, но передавать такой объём на клиент не стоит.