При разработке конфигураций на платформе 1С часто возникает необходимость программно удалить строки из табличной части (ТЧ) документа. Начинающие разработчики нередко сталкиваются с тем, что стандартная конструкция Для каждого работает некорректно: строки удаляются не все, возникают ошибки итератора или непредсказуемое поведение системы. Давайте разберем, почему это происходит и как правильно решать эту задачу.
Когда мы используем Для каждого, платформа 1С создает специальный внутренний итератор, который проходит по коллекции по порядку. Если внутри цикла мы удаляем текущую строку, индекс всех последующих элементов смещается. В итоге итератор «перескакивает» через следующую строку или теряет ориентиры, из-за чего цикл завершается раньше времени, пропуская элементы, которые должны были быть обработаны.
Рассмотрим рабочие способы, которые позволят избежать этой «ловушки» и корректно очистить табличную часть.
Это самый безопасный и понятный способ. Суть его заключается в разделении логики поиска строк и их фактического удаления. Сначала мы «собираем» ссылки на строки, которые нужно удалить, в массив, а затем проходим по этому массиву и удаляем их из таблицы.
Разберем это по шагам:
// Сбор строк в массив
МассивСтрок = Новый Массив;
Для каждого СтрокаТовары Из Объект.Товары Цикл
Если СтрокаТовары.Номенклатура <> ВыбраннаяНоменклатура Тогда
МассивСтрок.Добавить(СтрокаТовары);
КонецЕсли;
КонецЦикла;
// Удаление по массиву
Для Каждого СтрокаМассива Из МассивСтрок Цикл
Объект.Товары.Удалить(СтрокаМассива);
КонецЦикла;
Этот метод считается более экономным с точки зрения оперативной памяти, так как не требует создания вспомогательного массива. Мы используем обычный цикл по индексу, но начинаем его с последнего элемента и идем к первому.
Почему это работает? Когда мы удаляем строку с индексом N, индексы элементов, стоящих до нее (от 0 до N-1), остаются неизменными. Это позволяет нам безопасно продолжать проверку оставшихся строк.
КоличествоСтрок = Объект.Товары.Количество();
Для к = 1 По КоличествоСтрок Цикл
// Берем индекс с конца: из общего количества вычитаем шаг цикла
ИндексСтроки = КоличествоСтрок - к;
ТекущаяСтрока = Объект.Товары.Получить(ИндексСтроки);
Если ТекущаяСтрока.Количество = 100 Тогда
Объект.Товары.Удалить(ТекущаяСтрока);
КонецЕсли;
КонецЦикла;
Если вам нужно пересобрать табличную часть на основе сложной логики (например, отфильтровать ненужные строки и оставить только определенные), проще всего выгрузить таблицу в ТаблицаЗначений, очистить основной объект и заполнить его заново.
// Выгружаем ТЧ во временную таблицу
ВременнаяТЗ = Объект.Товары.Выгрузить();
Объект.Товары.Очистить();
// Переносим обратно только нужное
Для каждого СтрокаИзТЗ Из ВременнаяТЗ Цикл
Если СтрокаИзТЗ.Статус = "ВНаличии" Тогда
НоваяСтрока = Объект.Товары.Добавить();
ЗаполнитьЗначенияСвойств(НоваяСтрока, СтрокаИзТЗ);
КонецЕсли;
КонецЦикла;
НайтиСтроки(), если ваше условие простое (равенство значений). Он вернет массив строк, которые можно сразу передать в цикл удаления.Объект.Товары должны быть согласованы с текущим состоянием формы владельца.Удалить() внутри циклов, если есть возможность воспользоваться очисткой и перезаполнением через ТаблицаЗначений.Теперь, когда мы проанализировали эти подходы, вы сможете выбирать наиболее подходящий метод для каждой конкретной ситуации. Помните, что самый надежный способ — это всегда сначала собрать данные, а потом совершать действия по модификации коллекции.