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