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

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

При работе с коллекцией ТаблицаЗначений часто возникает задача отфильтровать данные или удалить строки, не соответствующие определенному критерию. Начинающие разработчики часто сталкиваются с ситуацией, когда после выполнения цикла часть строк остается не удаленной.

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

Почему нельзя удалять строки в прямом цикле «Для каждого»

Рассмотрим стандартный ошибочный код прямого обхода:


// НЕПРАВИЛЬНЫЙ ПОДХОД
Для каждого Стр Из ТЗ Цикл
    Если Стр.Пометка = Ложь Тогда
        ТЗ.Удалить(Стр);
    КонецЕсли;
КонецЦикла;

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

Кроме того, с точки зрения производительности, поштучное удаление элементов из массива в цикле приводит к постоянному перераспределению памяти. На больших объемах данных (тысячи элементов) это вызывает алгоритмическую сложность O(N²), что существенно замедляет работу программы.

Способ 1. Использование метода Скопировать() с фильтром по структуре

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

Посмотрим на пример кода:


Отбор = Новый Структура("Пометка", Истина);
ДокиРезультат = ТЗ.Скопировать(Отбор);

Обратите внимание: данный метод работает только на точное равенство значений. С его помощью нельзя задать условия вида «не равно», «больше/меньше» или сложный диапазон значений.

Способ 2. Предварительный поиск строк через НайтиСтроки()

Если необходимо модифицировать исходный объект ТаблицаЗначений, удалив из него ненужные элементы по условию равенства, воспользуемся методом НайтиСтроки().

Разберем по шагам данный алгоритм:

  1. Находим все строки, подлежащие удалению, и получаем их в виде массива.
  2. Проходим по полученному массиву циклом и удаляем строки из исходной таблицы.

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

Поскольку массив КУдалению содержит фиксированные ссылки на строки исходной таблицы, изменение индексов самой таблицы значений во время цикла удаления не сбивает итератор массива.

Совет по оптимизации: если поиск выполняется неоднократно на большой таблице, можно ускорить операцию, предварительно заиндексировав нужную колонку с помощью вызова ТЗ.Индексы.Добавить("Пометка").

Способ 3. Заполнение промежуточного массива строк

Если условие удаления является сложным (например, включает проверку заполненности нескольких полей или вызов внешних функций), сформируем массив строк на удаление вручную.

Рассмотрим пример реализации:


мУдалить = Новый Массив;

// Первый проход: только анализируем и собираем ссылки на строки
Для каждого Стр Из ТЗ Цикл 
    Если Стр.Пометка = Ложь Тогда
        мУдалить.Добавить(Стр);
    КонецЕсли;
КонецЦикла;

// Второй проход: удаляем найденные строки
Для каждого Стр Из мУдалить Цикл 
    ТЗ.Удалить(Стр);
КонецЦикла;

Способ 4. Обход коллекции по индексу с конца

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

Проанализируем пример кода:


Индекс = ТЗ.Количество() - 1;
Пока Индекс >= 0 Цикл
    Стр = ТЗ[Индекс];
    Если Не Стр.Пометка Тогда
        ТЗ.Удалить(Индекс);
    КонецЕсли;
    Индекс = Индекс - 1;
КонецЦикла;

Способ 5. Обработка через Запрос к Таблице Значений

Если таблица содержит десятки тысяч строк или требуется применить сложные условия фильтрации (группировки, соединения, условия «ИЛИ»), наиболее эффективным решением будет передача таблицы значений в объект Запрос.

Разберем последовательность действий:

  1. Помещаем таблицу значений во временную таблицу с помощью объекта МенеджерВременныхТаблиц.
  2. Описываем условия отбора в секции ГДЕ текста запроса.
  3. Выгружаем результат выполнения запроса обратно в таблицу значений с помощью метода Выполнить().Выгрузить().

Особенности работы с формами в клиенто-серверном контексте

Помните, что объект ТаблицаЗначений доступен только на сервере или в толстом клиенте. На управляемой форме в тонком клиенте данные отображаются через объект ДанныеФормыКоллекция.

Поочередное удаление элементов из коллекции формы на клиенте приводит к множественным вызовам пересчета интерфейса. В таких случаях рекомендуем передать данные на сервер, преобразовать реквизит формы в объект прикладного типа методом РеквизитФормыВЗначение(), быстро отфильтровать таблицу одним из описанных способов и вернуть результат на форму вызовом ЗначениеВРеквизитФормы().

← На главную