Замена элемента массива во встроенном языке 1С: индекс, цикл, структуры
Содержание
Чтобы изменить значение в массиве 1С, присвойте новое значение элементу по индексу: Массив[2] = "Новое";. То же самое делает метод Массив.Установить(2, "Новое"). Нумерация идёт с нуля, поэтому [2] — это третий элемент.
Частая ошибка новичка — менять элемент через переменную цикла Для Каждого. Код Элемент = 0; внутри такого цикла массив не меняет: перезаписывается только переменная. Ниже — рабочие способы для простых значений, структур и замены по условию. Всё описанное относится к встроенному языку платформы 8.3 и не зависит от конфигурации.
Присваивание по индексу и метод Установить
У массива два равноценных способа записать значение в существующую ячейку.
Цвета = Новый Массив;
Цвета.Добавить("красный"); // индекс 0
Цвета.Добавить("зелёный"); // индекс 1
Цвета.Добавить("синий"); // индекс 2
// Способ 1: квадратные скобки
Цвета[1] = "жёлтый";
// Способ 2: метод Установить(Индекс, Значение)
Цвета.Установить(2, "фиолетовый");
// Результат: красный, жёлтый, фиолетовый
Квадратные скобки короче и читаются привычнее. Установить() удобен, когда индекс и значение вычисляются в одном выражении или когда хочется явно показать, что ячейка перезаписывается. Для чтения парой к нему идёт Получить(Индекс).
Что нужно помнить про индексы:
- 🔢 первый элемент —
[0], последний —[Массив.ВГраница()]; - 📏
ВГраница()всегда равнаКоличество() - 1, у пустого массива это-1; - 🚫 присваивание работает только в существующую ячейку. Записать в
[Массив.Количество()]нельзя — для новых элементов естьДобавить()иВставить().
Тип значения в ячейке можно менять свободно. Массив в 1С не типизирован: в ячейке, где было число, может оказаться строка, ссылка или Неопределено.
Многомерный массив
Конструктор с несколькими параметрами создаёт массив массивов. Индексы указываются подряд:
Сетка = Новый Массив(3, 4); // 3 строки по 4 ячейки, все Неопределено
Сетка[0][3] = 100; // первая строка, четвёртая ячейка
Сетка[2][0] = "итог";
Каждый вложенный массив — обычный Массив, поэтому к нему применимы те же методы: Сетка[1].Установить(2, 5).
Как изменить элементы массива в цикле
Здесь кроется главная ловушка. Сравните два фрагмента:
Цены = Новый Массив;
Цены.Добавить(100);
Цены.Добавить(250);
Цены.Добавить(80);
// НЕ работает: меняется только переменная Цена
Для Каждого Цена Из Цены Цикл
Цена = Цена * 1.2;
КонецЦикла;
// Цены по-прежнему 100, 250, 80
// Работает: обращение к ячейке по индексу
Для Индекс = 0 По Цены.ВГраница() Цикл
Цены[Индекс] = Цены[Индекс] * 1.2;
КонецЦикла;
// Цены: 120, 300, 96
Переменная цикла Для Каждого получает значение ячейки. Новое значение, присвоенное переменной, в массив не возвращается. Для чисел, строк, дат и булевых значений менять нужно только через индекс.
Пересчитаем пример: 100 × 1,2 = 120; 250 × 1,2 = 300; 80 × 1,2 = 96. Результат совпадает с комментарием.
Когда массив пустой
Цикл Для Индекс = 0 По Цены.ВГраница() на пустом массиве не выполнится ни разу: граница равна -1, и начальное значение 0 уже больше конечного. Отдельная проверка Если Цены.Количество() > 0 для такого цикла не нужна.
Удаление вместо замены
Если часть элементов надо не заменить, а убрать, прямой цикл по индексу сломается: после Удалить() элементы сдвигаются, и следующий пропускается. Идите с конца:
Всего = Цены.Количество();
Для Сч = 1 По Всего Цикл
Индекс = Всего - Сч;
Если Цены[Индекс] < 100 Тогда
Цены.Удалить(Индекс);
КонецЕсли;
КонецЦикла;
Граница Всего посчитана до цикла, а индекс берётся от этого числа, а не от меняющегося Количество(). При обходе с конца удаление не сдвигает ещё не проверенные элементы.
Изменение значений в массиве структур
С массивом структур всё наоборот: Для Каждого подходит. Структура — объект, и переменная цикла указывает на тот же объект, что лежит в массиве. Меняя поле, вы меняете элемент.
Товары = Новый Массив;
Товары.Добавить(Новый Структура("Наименование, Количество, Цена", "Бумага А4", 10, 350));
Товары.Добавить(Новый Структура("Наименование, Количество, Цена", "Скрепки", 50, 40));
// Поле меняется прямо в элементе массива
Для Каждого Товар Из Товары Цикл
Товар.Цена = Товар.Цена + 10;
КонецЦикла;
// Цены: 360 и 50
// То же по индексу
Товары[1].Количество = 45;
Три операции, которые путают между собой:
| Что пишем | Что произойдёт |
|---|---|
Товар.Цена = 500 | изменится поле в элементе массива |
Товар.Вставить("Цена", 500) | изменит поле, а если его не было — добавит |
Товар = Новый Структура(...) | изменится только переменная, в массиве останется старая структура |
Чтобы заменить структуру целиком, присвойте её ячейке: Товары[0] = Новый Структура("Наименование, Количество, Цена", "Бумага А3", 5, 700);.
Обращение к полю, которого нет
Присваивание Товар.Скидка = 5 упадёт с ошибкой Поле объекта не обнаружено (Скидка), если такого ключа в структуре нет. Варианты:
- ✅
Товар.Вставить("Скидка", 5)— создаст ключ или перезапишет существующий; - ✅
Если Товар.Свойство("Скидка") Тогда ... КонецЕсли— сначала проверить, потом менять.
Если в массиве разнородные структуры (часть собрана из одного места, часть из другого), Вставить() надёжнее прямого присваивания.
Поиск элемента и замена по условию
Замена первого найденного значения
Метод Найти() возвращает индекс первого совпадения или Неопределено:
Индекс = Цвета.Найти("жёлтый");
Если Индекс <> Неопределено Тогда
Цвета[Индекс] = "оранжевый";
КонецЕсли;
Проверка на Неопределено обязательна. Без неё строка Цвета[Неопределено] = ... вызовет ошибку выполнения.
Замена всех вхождений
Найти() останавливается на первом совпадении. Для замены всех одинаковых значений нужен проход по индексам:
Заменено = 0;
Для Индекс = 0 По Цвета.ВГраница() Цикл
Если Цвета[Индекс] = "жёлтый" Тогда
Цвета[Индекс] = "оранжевый";
Заменено = Заменено + 1;
КонецЕсли;
КонецЦикла;
Сообщить(СтрШаблон("Заменено элементов: %1", Заменено));
СтрШаблон сам приводит число к строке. При склейке через + используйте Формат(Заменено, "ЧГ=0"), иначе на больших числах появится разделитель групп разрядов.
Замена пустых значений на значение по умолчанию
Типичная практическая задача: массив собран из результата запроса, и часть ячеек пустая. Перед расчётом их заменяют нулём:
Для Индекс = 0 По Суммы.ВГраница() Цикл
Если Суммы[Индекс] = Null Или Суммы[Индекс] = Неопределено Тогда
Суммы[Индекс] = 0;
КонецЕсли;
КонецЦикла;
Если в ячейках ожидаются только числа, удобнее проверить тип: Если ТипЗнч(Суммы[Индекс]) <> Тип("Число") Тогда. Такое условие поймает и Null, и Неопределено, и случайно попавшую строку.
Поиск в массиве структур по значению поля
Найти() сравнивает структуры как объекты, а не по содержимому. Он найдёт только ту же самую структуру, а не другую с теми же полями. Поэтому ищем по полю вручную:
Для Каждого Товар Из Товары Цикл
Если Товар.Наименование = "Скрепки" Тогда
Товар.Цена = 45;
Прервать; // уберите, если нужно обновить все совпадения
КонецЕсли;
КонецЦикла;
Если поиск по полю нужен постоянно и элементов тысячи, соберите рядом Соответствие «ключ → структура». Поиск по ключу в соответствии не требует перебора, а меняются поля всё той же структуры из массива.
ПоНаименованию = Новый Соответствие;
Для Каждого Товар Из Товары Цикл
ПоНаименованию.Вставить(Товар.Наименование, Товар);
КонецЦикла;
Найденный = ПоНаименованию.Получить("Бумага А4");
Если Найденный <> Неопределено Тогда
Найденный.Количество = 12; // изменится и элемент массива
КонецЕсли;
Ссылки, копии и неизменяемые массивы
Многие «странные» эффекты при замене значений объясняются тем, что массив — объект, а переменная хранит ссылку на него.
Присваивание не копирует массив
Исходный = Новый Массив;
Исходный.Добавить(1);
Копия = Исходный; // это та же коллекция
Копия[0] = 99;
// Исходный[0] тоже равен 99
Чтобы изменить копию и не тронуть оригинал, создайте новый массив. Для простых значений хватит такого кода:
Копия = Новый Массив;
Для Каждого Значение Из Исходный Цикл
Копия.Добавить(Значение);
КонецЦикла;
Для массива структур этого мало: в новом массиве окажутся те же структуры, и правка поля отразится в обоих. Нужна глубокая копия. В типовых конфигурациях на БСП есть функция ОбщегоНазначения.СкопироватьРекурсивно(), она копирует вложенные массивы и структуры.
Параметр Знач не спасает от изменений
Процедура Пересчитать(Знач Цены) защищает только переменную: присвоить ей новый массив внутри процедуры можно без последствий для вызывающего кода. Но Цены[0] = 0 внутри процедуры изменит исходный массив, потому что копируется ссылка, а не сама коллекция. Если процедура не должна портить данные, передайте ей копию.
ФиксированныйМассив
ФиксированныйМассив создаётся из обычного массива и запрещает изменения: у него нет методов Установить, Добавить, Удалить, присвоить значение ячейке тоже нельзя. Такие массивы часто приходят из повторно используемых модулей и параметров сеанса.
Чтобы поменять значение, сделайте изменяемую копию:
Изменяемый = Новый Массив(ФиксированныйСписок);
Изменяемый[0] = "новое значение";
Конструктор Новый Массив(<ФиксированныйМассив>) возвращает обычный массив с теми же элементами. Исходный фиксированный массив останется прежним.
Ошибки при замене значений и граничные случаи
ВГраница(). Частая причина — цикл до Количество() вместо ВГраница() или нумерация с единицы. Для новой ячейки используйте Добавить().Вставить() или проверьте через Свойство().Для Каждого или переменной, куда структура была заменена целиком. Пишите в ячейку по индексу.Новый Массив(...).Ещё несколько граничных случаев, на которых спотыкаются:
- Индекс — дробное число. Если индекс получен вычислением, например делением, округлите его явно:
Цел(Позиция / 2). Не полагайтесь на то, что платформа сама отбросит дробную часть. - Индекс пришёл из
Найти(). Без проверки наНеопределенокод упадёт, как только значения в массиве не окажется. - Замена во время перебора
Для Каждого. ЗаписьЦены[Индекс] = ...внутри такого цикла технически возможна, если вести счётчик отдельно, но читается плохо. Если меняете ячейки — сразу берите цикл по индексу. - Сравнение с
НеопределеноиNull. Значения из запроса могут прийти какNull, а «пустые» ячейки нового массива —Неопределено. При замене пустых значений проверяйте оба варианта.
Какой способ изменения массива выбрать
| Задача | Способ | На что смотреть |
|---|---|---|
| Заменить элемент, индекс известен | Массив[i] = Значение или Установить(i, Значение) | индекс от 0 до ВГраница() |
| Изменить все простые значения | цикл Для Индекс = 0 По ВГраница() | не Для Каждого |
| Изменить поле у всех структур | Для Каждого + Элемент.Поле = ... | ключ должен существовать |
| Заменить первое совпадение | Найти() + проверка на Неопределено | ищет только первое |
| Заменить все совпадения | цикл по индексу с условием | счётчик замен для контроля |
| Найти структуру по полю | перебор или Соответствие по ключу | Найти() по содержимому не ищет |
| Удалить элементы по условию | обратный цикл с Удалить() | границу считать до цикла |
| Изменить фиксированный массив | Новый Массив(Фиксированный) | меняется копия |
Если массив растёт до десятков тысяч строк с несколькими полями, а замены идут по условиям, подумайте о ТаблицаЗначений. У неё есть НайтиСтроки() с отбором по нескольким колонкам и индексы для быстрого поиска. Колонку таблицы можно выгрузить в массив методом ВыгрузитьКолонку() и загрузить обратно через ЗагрузитьКолонку().
Частые вопросы
Как заменить значение в массиве, если индекс неизвестен?
Найти(Значение), проверьте, что результат не Неопределено, и присвойте новое значение ячейке с этим индексом.Можно ли вставить новое значение между элементами, а не заменить?
Вставить(Индекс, Значение). Элементы начиная с этого индекса сдвинутся на одну позицию вправо, количество вырастет на один.Чем Установить() отличается от присваивания через квадратные скобки?
Есть ли метод, который заменит сразу все одинаковые значения?
Как поменять местами два элемента массива?
Врем = М[0]; М[0] = М[1]; М[1] = Врем;.