Массив в 1С 8.3: создание, заполнение и загрузка данных
Содержание
Массив в 1С вводят кодом на встроенном языке: Мас = Новый Массив; создаёт пустую коллекцию, а Мас.Добавить(Значение) кладёт в неё элементы. Индексы начинаются с нуля, тип элементов не фиксирован: в одном массиве могут лежать число, строка и ссылка на справочник.
Пользователь в режиме «Предприятие» массив напрямую не вводит — у него нет такого поля. Для него программист даёт список значений или табличную часть, а уже из них код получает массив одной строкой. Ниже пять способов: от ручного перечисления значений до загрузки из файла.
Как устроен массив в 1С и чем он отличается от других коллекций
Массив — упорядоченный набор значений с доступом по индексу. Первый элемент — Мас[0], последний — Мас[Мас.ВГраница()]. У пустого массива ВГраница() возвращает -1, а Количество() — 0.
Основные методы, которые понадобятся в любом способе заполнения:
| Метод | Что делает |
|---|---|
Добавить(Значение) | Добавляет элемент в конец |
Вставить(Индекс, Значение) | Вставляет элемент в позицию, остальные сдвигаются |
Установить(Индекс, Значение) | Заменяет значение существующего элемента |
Получить(Индекс) | Возвращает элемент, то же, что Мас[Индекс] |
Найти(Значение) | Возвращает индекс первого совпадения или Неопределено |
Удалить(Индекс) | Удаляет элемент по индексу |
Количество() / ВГраница() | Число элементов / последний индекс |
Очистить() | Удаляет все элементы |
Когда брать массив, а когда другую коллекцию:
- 📦 Массив — простой список значений: ссылки для параметра запроса, строки после разбора текста, промежуточный результат.
- 📋 Список значений — когда нужны представление, пометка или показ пользователю на форме.
- 🗂 Таблица значений — когда у каждой строки несколько колонок.
- 🔑 Соответствие — когда нужен быстрый поиск по ключу и уникальность.
Массив нельзя сделать типом реквизита справочника или документа. Если массив нужно сохранить в базе, используйте табличную часть или реквизит типа ХранилищеЗначения.
Способ 1. Ручной ввод значений через конструктор массива
Самый прямой способ ввести массив — перечислить значения в коде. Конструктор Новый Массив принимает необязательное число элементов.
// Пустой массив, элементы добавляем по одному
Месяцы = Новый Массив;
Месяцы.Добавить("Январь");
Месяцы.Добавить("Февраль");
Месяцы.Добавить("Март");
// Массив заданного размера: три элемента со значением Неопределено
Ставки = Новый Массив(3);
Ставки[0] = 0;
Ставки[1] = 10;
Ставки[2] = 20;
Во втором варианте Добавить не нужен: ячейки уже есть, их просто заполняют по индексу. Если вызвать Ставки.Добавить(5), массив вырастет до четырёх элементов.
Многомерный массив
Конструктор принимает несколько размерностей. Новый Массив(3, 4) создаёт массив из трёх элементов, каждый из которых — массив из четырёх.
Матрица = Новый Массив(3, 4);
Для Стр = 0 По 2 Цикл
Для Кол = 0 По 3 Цикл
Матрица[Стр][Кол] = Стр * 4 + Кол;
КонецЦикла;
КонецЦикла;
// Матрица[2][3] = 11
Проверка: для Стр = 2, Кол = 3 получаем 2 × 4 + 3 = 11.
Быстрый ввод строкой через СтрРазделить
Когда значений много, перечислять их через Добавить неудобно. Функция СтрРазделить (платформа 8.3.6 и новее) превращает строку в массив за одну строку кода.
Коды = СтрРазделить("001,002,003,004", ",", Ложь);
// Коды.Количество() = 4, элементы — строки
Третий параметр Ложь выбрасывает пустые подстроки: строка "001,,002" даст два элемента, а не три. Обратная операция — СтрСоединить(Коды, ";").
Элементы после СтрРазделить всегда строки. Если нужны числа, приводите каждый элемент через Число() в цикле, иначе сравнение Коды[0] = 1 вернёт Ложь.
Способ 2. Заполнение массива в цикле
Цикл — основной способ заполнить массив по правилу: числа по порядку, даты периода, отфильтрованные элементы другой коллекции.
// Даты каждого дня месяца
ДатыМесяца = Новый Массив;
ТекДата = НачалоМесяца(ТекущаяДатаСеанса());
Конец = КонецМесяца(ТекДата);
Пока ТекДата <= Конец Цикл
ДатыМесяца.Добавить(ТекДата);
ТекДата = ТекДата + 86400; // сутки в секундах
КонецЦикла;
Для перебора уже заполненного массива удобнее Для Каждого:
Сумма = 0;
Для Каждого Элемент Из Ставки Цикл
Сумма = Сумма + Элемент;
КонецЦикла;
// для Ставки = 0, 10, 20 получим 30
Заполнение без дублей
Если значения могут повторяться, проверяйте их перед добавлением. На небольших массивах хватает Найти, на десятках тысяч элементов быстрее работает соответствие.
// До пары тысяч элементов
Если Уникальные.Найти(Значение) = Неопределено Тогда
Уникальные.Добавить(Значение);
КонецЕсли;
// Большие объёмы: ключи соответствия уникальны
Набор = Новый Соответствие;
Для Каждого Значение Из Исходный Цикл
Набор.Вставить(Значение, Истина);
КонецЦикла;
Уникальные = Новый Массив;
Для Каждого КлючИЗначение Из Набор Цикл
Уникальные.Добавить(КлючИЗначение.Ключ);
КонецЦикла;
Найти каждый раз перебирает массив сначала, поэтому на 50 000 элементов цикл с проверкой выполняется заметно дольше варианта с соответствием.
Способ 3. Массив из результата запроса
Самый частый случай в типовых конфигурациях — получить из базы список ссылок. Не перебирайте выборку вручную: метод ВыгрузитьКолонку у таблицы значений сразу возвращает массив.
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
| Контрагенты.Ссылка КАК Ссылка
|ИЗ
| Справочник.Контрагенты КАК Контрагенты
|ГДЕ
| НЕ Контрагенты.ПометкаУдаления
| И НЕ Контрагенты.ЭтоГруппа";
МассивКонтрагентов = Запрос.Выполнить().Выгрузить().ВыгрузитьКолонку("Ссылка");
Код выполняйте на сервере: объект Запрос на тонком клиенте недоступен.
Массив как параметр запроса
Обратная задача — передать массив в запрос и отобрать по нему данные. Для этого служит условие В (&Параметр):
Запрос.Текст =
"ВЫБРАТЬ
| Номенклатура.Ссылка,
| Номенклатура.Наименование
|ИЗ
| Справочник.Номенклатура КАК Номенклатура
|ГДЕ
| Номенклатура.Ссылка В (&СписокТоваров)";
Запрос.УстановитьПараметр("СписокТоваров", МассивТоваров);
Пустой массив в параметре В (&...) не вызывает ошибку, но запрос вернёт пустой результат. Если пустой список должен означать «без отбора», проверяйте МассивТоваров.Количество() = 0 до выполнения и убирайте условие из текста.
Способ 4. Загрузка массива из Excel, JSON и XML
Внешние данные почти всегда приходят файлом. Платформа 8.3 читает все три формата без внешних компонент.
Excel через табличный документ
Метод Прочитать у табличного документа открывает .xlsx и .xls без установленного Excel. Код ниже собирает значения первой колонки в массив, пропуская заголовок.
ТабДок = Новый ТабличныйДокумент;
ТабДок.Прочитать(ИмяФайла);
Артикулы = Новый Массив;
Для НомерСтроки = 2 По ТабДок.ВысотаТаблицы Цикл
Текст = СокрЛП(ТабДок.Область(НомерСтроки, 1).Текст);
Если ЗначениеЗаполнено(Текст) Тогда
Артикулы.Добавить(Текст);
КонецЕсли;
КонецЦикла;
Файл должен лежать там, где выполняется код. Если пользователь выбирает файл на своём компьютере, а код работает на сервере, сначала передайте файл на сервер через ПоместитьФайл или НачатьПомещениеФайлаНаСервер и прочитайте его из временного файла.
JSON
JSON-массив вида [...] платформа сразу превращает в объект Массив.
Чтение = Новый ЧтениеJSON;
Чтение.УстановитьСтроку("[""А-101"", ""Б-202"", ""В-303""]");
Данные = ПрочитатьJSON(Чтение);
Чтение.Закрыть();
// Данные — Массив из трёх строк
Если в массиве лежат объекты {...}, каждый станет Структурой. Когда ключи содержат пробелы или начинаются с цифры, структура их не примет: передайте вторым параметром Истина, и объекты прочитаются в Соответствие. Чтение из файла — Чтение.ОткрытьФайл(ИмяФайла) вместо УстановитьСтроку.
XML
Для простого файла со списком значений хватит последовательного чтения через ЧтениеXML:
// Файл: <items><item>А-101</item><item>Б-202</item></items>
Чтение = Новый ЧтениеXML;
Чтение.ОткрытьФайл(ИмяФайла);
Значения = Новый Массив;
ВнутриItem = Ложь;
Пока Чтение.Прочитать() Цикл
Если Чтение.ТипУзла = ТипУзлаXML.НачалоЭлемента И Чтение.Имя = "item" Тогда
ВнутриItem = Истина;
ИначеЕсли Чтение.ТипУзла = ТипУзлаXML.Текст И ВнутриItem Тогда
Значения.Добавить(Чтение.Значение);
ИначеЕсли Чтение.ТипУзла = ТипУзлаXML.КонецЭлемента Тогда
ВнутриItem = Ложь;
КонецЕсли;
КонецЦикла;
Чтение.Закрыть();
Для сложных XML со вложенными структурами удобнее модель DOM или XDTO, но для плоского списка последовательное чтение быстрее и проще.
| Источник | Чем читать | Что получаем |
|---|---|---|
| Строка с разделителями | СтрРазделить | Массив строк |
| Запрос к базе | Выгрузить().ВыгрузитьКолонку() | Массив ссылок или значений |
| Excel | ТабличныйДокумент.Прочитать + цикл | Массив строк из ячеек |
| JSON | ЧтениеJSON + ПрочитатьJSON | Массив, структуры или соответствия |
| XML | ЧтениеXML + цикл | Массив строк из узлов |
Способ 5. Как дать пользователю ввести список значений
Если массив нужно ввести не программисту, а бухгалтеру или кладовщику, на форме обработки делают реквизит типа СписокЗначений. Пользователь видит таблицу и заполняет её построчно, подбором или вставкой из буфера обмена.
Порядок для управляемой формы:
- В конфигураторе или расширении откройте форму обработки и добавьте реквизит формы типа
СписокЗначений, напримерСписокАртикулов. - В свойстве реквизита задайте тип значений: строка, число или ссылка на нужный справочник.
- Перетащите реквизит на форму — получится таблица, в которой пользователь добавляет строки.
- В серверной процедуре команды получите массив:
Мас = СписокАртикулов.ВыгрузитьЗначения();.
Обратно массив загружают так: СписокАртикулов.ЗагрузитьЗначения(Мас);.
Пользователю удобно вставить колонку, скопированную из Excel. Добавьте на форму многострочное поле ввода текста, а в команде разберите его через СтрРазделить(Текст, Символы.ПС, Ложь). Не забудьте СокрЛП для каждого элемента: из Excel часто приходят хвостовые пробелы и символ возврата каретки.
В типовых отчётах похожий ввод уже есть: в отборе с видом сравнения «В списке» пользователь открывает окно и набирает значения. Программно такой отбор и есть массив или список значений.
Фиксированный массив, копирование и передача между клиентом и сервером
Обычный массив меняется: в него добавляют и из него удаляют элементы. Когда коллекция должна оставаться неизменной (например, её отдают в общий модуль с повторным использованием значений), берут ФиксированныйМассив.
ДопустимыеСтавки = Новый ФиксированныйМассив(Ставки);
// ДопустимыеСтавки.Добавить(...) вызовет ошибку: метода нет
Копия, а не ссылка
Присваивание Мас2 = Мас1 не копирует массив. Обе переменные смотрят на один объект, и Мас2.Добавить(1) изменит и Мас1. Чтобы получить независимую копию, есть короткий приём:
Копия = Новый Массив(Новый ФиксированныйМассив(Исходный));
Копия получается поверхностной: если внутри лежат другие массивы или структуры, они останутся общими. Для глубокой копии нужно рекурсивно обойти вложенные коллекции.
Клиент и сервер
Массив из примитивных значений и ссылок спокойно передаётся параметром в серверную процедуру и возвращается обратно. А вот массив, внутри которого лежит запрос, табличный документ или объект справочника, через границу клиент–сервер не пройдёт. Передавайте ссылки и примитивы, а тяжёлые объекты создавайте там, где они используются.
Типичные ошибки при работе с массивами
Ошибки с массивами однообразны, и почти все ловятся отладчиком за минуту.
- 🔢 Выход за границы индекса. Цикл
Для Сч = 0 По Мас.Количество() Циклделает лишний проход: последний индекс —Количество() - 1. ПишитеПо Мас.ВГраница()или используйтеДля Каждого. - 🗑 Удаление в прямом цикле. После
Мас.Удалить(Сч)элементы сдвигаются, и следующий пропускается. Удаляйте с конца:
Для Сч = 1 По Мас.Количество() Цикл
Индекс = Мас.Количество() - Сч;
Если Мас[Индекс] = 0 Тогда
Мас.Удалить(Индекс);
КонецЕсли;
КонецЦикла;
Здесь граница цикла считается один раз при входе, а индекс идёт от последнего элемента к первому. Удаление элемента не влияет на ещё не проверенные позиции.
- 🔤 Строка вместо числа. После
СтрРазделитьили чтения Excel элементы — строки.Найти(5)в массиве"5"вернётНеопределено. - 🔗 Неожиданная правка «копии». Изменили
Мас2, а поменялся иМас1— значит, копии не было, см. приём с фиксированным массивом выше. - ❓
Найтине проверили наНеопределено. КодМас.Удалить(Мас.Найти(Х))упадёт, если значения нет. - 🐢
Найтивнутри большого цикла. На десятках тысяч элементов это квадратичная сложность; берите соответствие.
Частые вопросы о массивах в 1С
Можно ли отсортировать массив в 1С?
ЗагрузитьЗначения, вызовите СортироватьПоЗначению() и выгрузите обратно через ВыгрузитьЗначения().Как проверить, что переменная — массив?
ТипЗнч(Переменная) = Тип("Массив"). Для фиксированного массива — Тип("ФиксированныйМассив").Как превратить массив в строку для вывода или лога?
СтрСоединить(Мас, ", "). Если внутри числа или ссылки, сначала соберите массив их строковых представлений.Есть ли ограничение на размер массива?
Чем ВГраница отличается от Количество?
Количество() — число элементов, ВГраница() — индекс последнего, всегда на единицу меньше. Для пустого массива это 0 и -1.