Как правильно удалить строки из табличной части документа по условию в 1С

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При разработке и доработке конфигураций 1С часто возникает задача удалить из табличной части документа строки, соответствующие определенному критерию. Начинающие разработчики нередко сталкиваются с ошибками пропуска строк или выходом за границы массива при попытке прямого обхода коллекции. Разберем по шагам, почему возникает эта проблема, и рассмотрим проверенные способы корректного удаления строк.

Проблема прямого перебора: если мы выполняем обычный цикл Для Каждого или перебираем строки по возрастанию индекса и вызываем метод ТЧ.Удалить(...), все последующие строки смещаются на одну позицию назад (влево). В результате итератор перескакивает через следующую строку, не проверяя ее, а при переборе по индексам в конце цикла платформа выдает ошибку выхода индекса за пределы диапазона.

Способ 1. Удаление строк через метод НайтиСтроки (для простого равенства)

Если условием для удаления является точное совпадение значений одной или нескольких колонок, наиболее лаконичным решением является метод НайтиСтроки(). Этот метод возвращает массив ссылок на строки табличной части.

Посмотрим на пример реализации данного подхода:


// Формируем отбор по значению реквизита
Отбор = Новый Структура("Номенклатура", ВыбраннаяНоменклатура);
СтрокиКУдалению = Объект.Товары.НайтиСтроки(Отбор);

// Обходим полученный массив и удаляем строки из табличной части
Для Каждого СтрокаТЧ Из СтрокиКУдалению Цикл
    Объект.Товары.Удалить(СтрокаТЧ);
КонецЦикла;

В этом случае удаление выполняется корректно, так как метод Удалить() может принимать в качестве параметра не только числовой индекс, но и саму строку табличной части (СтрокаТабличнойЧасти). Коллекция сама находит и удаляет нужный элемент независимо от смещения индексов остальных строк.

Способ 2. Двухэтапное удаление через массив (для произвольных сложных условий)

Проанализируем ситуацию, когда критерий отбора сложнее простого равенства: например, требуется проверить диапазон дат, неравенство, сравнить числовые показатели или проверить заполненность нескольких взаимосвязанных полей. Метод НайтиСтроки() в таком сценарии не подойдет, так как структура отбора работает только на строгое равенство.

Разберем алгоритм решения через предварительный сбор строк в массив:

  1. Создаем пустой массив для накопления строк, подлежащих удалению.
  2. Обходим табличную часть стандартным циклом Для Каждого, проверяем любые сложные условия и добавляем подходящие строки в массив.
  3. Вторым циклом перебираем заполненный массив и удаляем строки из табличной части.

МассивУдаляемых = Новый Массив;

// Этап 1: поиск и сбор строк по любому условию
Для Каждого СтрокаТЧ Из Объект.Товары Цикл
    Если СтрокаТЧ.Количество <= 0 Или СтрокаТЧ.Сумма < 0 Тогда
        МассивУдаляемых.Добавить(СтрокаТЧ);
    КонецЕсли;
КонецЦикла;

// Этап 2: удаление отобранных строк
Для Каждого СтрокаТЧ Из МассивУдаляемых Цикл
    Объект.Товары.Удалить(СтрокаТЧ);
КонецЦикла;

Способ 3. Обход таблицы с конца через цикл Пока

Если мы хотим удалить строки за один проход без выделения дополнительной памяти под массив, можно выполнить обход таблицы с конца к началу по индексам. При удалении элемента с конца сдвигаются только те строки, которые уже были проверены на предыдущих шагах, поэтому ни одна строка не будет пропущена.

Так как в языке 1С цикл Для поддерживает только шаг +1, обратный обход реализуется с помощью цикла Пока:


Индекс = Объект.Товары.Количество() - 1;

Пока Индекс >= 0 Цикл
    СтрокаТЧ = Объект.Товары[Индекс];
    
    Если СтрокаТЧ.ПометкаУдаления = Истина Тогда
        Объект.Товары.Удалить(Индекс);
    КонецЕсли;
    
    Индекс = Индекс - 1;
КонецЦикла;

Способ 4. Оптимизация для больших табличных частей (Выгрузить и Загрузить)

Рассмотрим случай, когда табличная часть документа содержит тысячи или десятки тысяч строк. Метод Удалить() при многократном вызове на больших объемах данных начинает работать медленно из-за постоянного перестроения внутреннего массива в памяти.

Для ускорения обработки сотен и тысяч строк эффективнее выгрузить данные во временную таблицу значений, отфильтровать нужные строки и загрузить результат обратно:


// 1. Выгружаем табличную часть во временную таблицу значений
ВременнаяТаблица = Объект.Товары.Выгрузить();

// 2. Создаем массив строк на удаление или отбираем нужные
СтрокиКУдалению = ВременнаяТаблица.НайтиСтроки(Новый Структура("Удалить", Истина));
Для Каждого Стр Из СтрокиКУдалению Цикл
    ВременнаяТаблица.Строки.Удалить(Стр);
КонецЦикла;

// 3. Загружаем очищенную таблицу обратно в табличную часть
Объект.Товары.Загрузить(ВременнаяТаблица);

Также выгруженную таблицу можно передать в качестве параметра в Запрос, выполнить быстрое условие ГДЕ средствами СУБД и загрузить результат запроса обратно в табличную часть через Объект.Товары.Загрузить(РезультатЗапроса.Выгрузить()).

← На главную