Заполнение массива во встроенном языке 1С 8.3: вручную, в цикле и из запроса

· 9 мин

Содержание

Заполнить массив в 1С проще всего методом Добавить(): создаёте Новый Массив и в цикле добавляете значения в конец. Если данные лежат в базе, быстрее взять их запросом и выгрузить колонку: Запрос.Выполнить().Выгрузить().ВыгрузитьКолонку("Ссылка") сразу вернёт готовый массив. Строку с разделителями превращает в массив функция СтрРазделить().

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

Как устроен массив в 1С и какие способы заполнения бывают

Массив — упорядоченная коллекция значений с доступом по индексу. Несколько свойств, которые влияют на заполнение:

  • 🔢 индексы начинаются с нуля: у массива из 5 элементов последний индекс 4;
  • 📏 Количество() возвращает число элементов, ВГраница() — последний индекс (у пустого массива это −1);
  • 🧩 в одном массиве можно держать значения разных типов: числа, строки, ссылки, другие массивы;
  • 🔗 массив — ссылочный объект: присваивание Б = А не копирует данные, обе переменные указывают на один массив;
  • 🔒 ФиксированныйМассив изменить нельзя — заполнить его можно только при создании.

Способы заполнения сведём в таблицу:

СпособКогда применятьНа что смотреть
Добавить() вручнуюнесколько известных значенийсамый читаемый вариант
Вставить() / Установить()нужна конкретная позицияиндекс должен быть в границах
Цикл Для / Пока / Для Каждогорасчётные значения, перебор коллекциине менять перебираемый массив
Запрос + ВыгрузитьКолонку()данные из базыодин запрос вместо запросов в цикле
СтрРазделить()строка с разделителямипустые части отбрасывает третий параметр

Заполнение массива вручную: Добавить(), Вставить() и Установить()

Три метода закрывают все ручные сценарии. Добавить(Значение) пишет в конец. Вставить(Индекс, Значение) ставит значение на позицию и сдвигает остальные вправо. Установить(Индекс, Значение) заменяет существующий элемент — то же самое делает запись через квадратные скобки.

Коды = Новый Массив;
Коды.Добавить("A01");
Коды.Добавить("B02");      // "A01", "B02"

Коды.Вставить(0, "000");   // "000", "A01", "B02"
Коды.Установить(1, "A99"); // "000", "A99", "B02"
Коды[2] = "B03";           // "000", "A99", "B03"

Вставить() с индексом, равным Количество(), работает как Добавить(): значение уходит в конец.

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

Конструктор с числом создаёт массив, где каждый элемент равен Неопределено. Дальше значения пишут по индексу:

ДниНедели = Новый Массив(7);
ДниНедели[0] = "Понедельник";
ДниНедели[1] = "Вторник";
// ... до ДниНедели[6]

Так удобно, когда позиция элемента сама несёт смысл: номер дня, месяца, квартала. Пустые ячейки проверяйте через ЗначениеЗаполнено() или сравнением с Неопределено.

Копия массива

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

Копия = Новый Массив(Новый ФиксированныйМассив(Исходный));
Копия.Добавить("новый"); // Исходный не изменится

Копия поверхностная: если внутри лежат другие массивы, они останутся общими.

Как заполнить массив данными из запроса

Это самый частый случай в реальных обработках: нужен список ссылок, ИНН, кодов. Не перебирайте справочник через Выбрать() у менеджера и тем более не делайте запрос на каждый элемент. Один запрос и выгрузка колонки решают задачу:

Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
|	Контрагенты.Ссылка КАК Ссылка
|ИЗ
|	Справочник.Контрагенты КАК Контрагенты
|ГДЕ
|	НЕ Контрагенты.ПометкаУдаления
|	И НЕ Контрагенты.ЭтоГруппа";

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

Выгрузить() возвращает таблицу значений, а ВыгрузитьКолонку() — массив значений одной колонки в порядке строк. Если нужны только уникальные значения, добавьте в запрос РАЗЛИЧНЫЕ — это дешевле, чем чистить дубли потом в коде.

Выборка с условием в коде

Когда отбор сложно выразить в запросе (проверка контрольной суммы, регулярное правило по строке), обходите выборку и добавляйте подходящие строки:

МассивИНН = Новый Массив;
Выборка = Запрос.Выполнить().Выбрать();
Пока Выборка.Следующий() Цикл
	Если СтрДлина(Выборка.ИНН) = 10 Тогда
		МассивИНН.Добавить(Выборка.ИНН);
	КонецЕсли;
КонецЦикла;

Для этого варианта поле ИНН должно быть в тексте запроса.

Обратная задача: массив как параметр запроса

Заполненный массив часто передают в следующий запрос как список для отбора:

Запрос.Текст = "... ГДЕ Документ.Контрагент В (&СписокКонтрагентов)";
Запрос.УстановитьПараметр("СписокКонтрагентов", МассивКонтрагентов);

ВыполнитьПакет() у пакетного запроса тоже возвращает массив — массив результатов. Результат третьего запроса пакета берут как Результаты[2].

Заполнение массива в цикле и из других коллекций

Цикл Для

Классика для расчётных значений. Заполним массив квадратами чисел от 1 до 10:

Квадраты = Новый Массив;
Для Н = 1 По 10 Цикл
	Квадраты.Добавить(Н * Н);
КонецЦикла;
// 1, 4, 9, ... 100 — всего 10 элементов

Цикл Для Каждого по другой коллекции

Так собирают массив из структуры, соответствия, табличной части:

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

Многие коллекции отдают массив сами, без цикла:

ИсточникКак получить массив
Таблица значений, табличная частьВыгрузитьКолонку("ИмяКолонки")
Список значенийВыгрузитьЗначения()
Строка с разделителямиСтрРазделить(Строка, ";", Ложь)
Выделенные строки динамического спискаЭлементы.Список.ВыделенныеСтроки

Разбор строки через СтрРазделить

Функция появилась в платформе 8.3.6. Третий параметр Ложь отбрасывает пустые части между двумя разделителями подряд:

Части = СтрРазделить("101;102;;103", ";", Ложь);
// "101", "102", "103" — три элемента, пустой пропущен

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

СтрРазделить() всегда возвращает строки. Для чисел и дат нужна явная конвертация, как в примере. Обратная операция — СтрСоединить(Массив, ", ") — склеивает элементы в одну строку.

Цикл Пока

Подходит, когда число итераций заранее неизвестно. Например, собираем даты начала месяцев за период:

Месяцы = Новый Массив;
ТекущаяДата = НачалоМесяца(ДатаНачала);
Пока ТекущаяДата <= ДатаОкончания Цикл
	Месяцы.Добавить(ТекущаяДата);
	ТекущаяДата = ДобавитьМесяц(ТекущаяДата, 1);
КонецЦикла;

При ДатаНачала = 15.01 и ДатаОкончания = 20.03 получится три элемента: 01.01, 01.02, 01.03.

Быстрое заполнение больших массивов

На массивах в сотни элементов разницы между способами не видно. Она появляется на десятках и сотнях тысяч. Что реально ускоряет:

  1. Данные из базы — одним запросом. Запрос в цикле — главный тормоз: каждая итерация идёт на сервер СУБД. Один запрос на 50 000 строк выполнится быстрее, чем 50 000 запросов по одной строке, на порядки.
  2. ВыгрузитьКолонку() вместо цикла по таблице. Платформа заполняет массив внутри себя, без интерпретации каждой строки кода.
  3. Уникальность — через соответствие, а не через Найти(). Найти() перебирает массив с начала. Проверка перед каждым добавлением даёт квадратичный рост: на 10 000 элементах это около 50 млн сравнений. Соответствие ищет ключ без перебора.
  4. Известный размер — сразу в конструктор. Новый Массив(N) и запись по индексу избавляют от постоянного роста массива. Выигрыш скромный, но в длинных циклах заметен.
  5. Меньше передач между клиентом и сервером. Заполняйте массив там, где лежат данные (на сервере), и передавайте на клиент готовый результат одним вызовом.

Пример быстрого отбора уникальных значений:

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

Порядок элементов сохраняется: в Уникальные попадает первое вхождение каждого значения.

В конфигурациях на БСП есть готовые процедуры: ОбщегоНазначенияКлиентСервер.ДополнитьМассив() добавляет элементы одного массива в другой (с параметром «только уникальные»), ОбщегоНазначенияКлиентСервер.СвернутьМассив() удаляет дубли. В типовых БП, ЗУП и УТ они доступны из любого модуля.

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

Многомерный массив в 1С — массив, элементы которого тоже массивы. Конструктор с несколькими числами создаёт такую структуру сразу:

Сетка = Новый Массив(3, 4); // 3 строки по 4 элемента
Для НомерСтроки = 0 По 2 Цикл
	Для НомерКолонки = 0 По 3 Цикл
		Сетка[НомерСтроки][НомерКолонки] = НомерСтроки * 4 + НомерКолонки;
	КонецЦикла;
КонецЦикла;
// Сетка[0] = 0, 1, 2, 3
// Сетка[2] = 8, 9, 10, 11

Обращение идёт двумя индексами подряд: Сетка[1][2] вернёт 6.

«Рваный» массив разной длины

Если строки разной длины, собирайте структуру вручную:

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

Если строки многомерной структуры нужно находить по ключу (по отделу, по контрагенту), удобнее соответствие, где значение — массив. Таблица значений лучше, когда у «строк» есть именованные колонки и нужна сортировка или свёртка.

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

  • ❌ Запись по несуществующему индексу. Массив[0] = 1 у пустого Новый Массив вызовет ошибку выхода индекса за границы. Для пустого массива используйте Добавить() либо создавайте его с размером.
  • ❌ Удаление элементов в прямом цикле. После Удалить() элементы сдвигаются, и следующий пропускается. Удаляйте с конца, зафиксировав границу до цикла:
ВГр = Числа.ВГраница();
Для Сч = 0 По ВГр Цикл
	Индекс = ВГр - Сч;
	Если Числа[Индекс] < 0 Тогда
		Числа.Удалить(Индекс);
	КонецЕсли;
КонецЦикла;
  • ❌ Изменение массива внутри Для Каждого по нему же. Результат непредсказуем: элементы пропускаются или обрабатываются дважды. Собирайте результат в новый массив.
  • ❌ «Копия» через присваивание. После Б = А и Б.Очистить() пустым окажется и А.
  • ❌ Склейка числа со строкой без формата. "Строка " + 1500 даст «1 500» с неразрывным пробелом. Для ключей и кодов пишите "Строка " + Формат(1500, "ЧГ=0").
  • ❌ Добавить() у фиксированного массива. Например, у значения из фиксированной структуры. Сначала сделайте обычную копию через Новый Массив(...).
Проверьте себя
Что вернёт ВГраница() у пустого массива?
Чем заполнены элементы после Новый Массив(3)?
Какой метод таблицы значений сразу возвращает массив?

Практические примеры: где массив нужен каждый день

Обработка выделенных строк списка

На форме списка выделенные пользователем строки уже лежат в массиве. Передайте его на сервер одним вызовом:

&НаКлиенте
Процедура ОбработатьВыделенные(Команда)
	Выделенные = Элементы.Список.ВыделенныеСтроки;
	Если Выделенные.Количество() = 0 Тогда
		Возврат;
	КонецЕсли;
	ОбработатьНаСервере(Выделенные);
КонецПроцедуры

Для динамического списка справочника или документа в массиве будут ссылки, их сразу можно передать параметром в запрос.

Список адресов для рассылки

Собрали адреса в массив, склеили в строку для поля «Кому»:

Адреса = Новый Массив;
Адреса.Добавить("buh@example.ru");
Адреса.Добавить("director@example.ru");
Кому = СтрСоединить(Адреса, "; ");
// "buh@example.ru; director@example.ru"

Загрузка кодов из текстового файла

Каждая строка файла — код номенклатуры. Читаем, разбиваем по переводам строки, отбрасываем пустые:

Текст = Новый ТекстовыйДокумент;
Текст.Прочитать(ПутьКФайлу, КодировкаТекста.UTF8);
Коды = СтрРазделить(Текст.ПолучитьТекст(), Символы.ПС, Ложь);

Дальше массив Коды уходит параметром в запрос ГДЕ Номенклатура.Код В (&Коды), и за один проход получаете все ссылки. Если в файле встречаются пробелы по краям, прогоните элементы через СокрЛП() перед запросом.

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

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