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

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

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

В чем заключается основная ошибка?

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

  1. Коллекция перестраивается: индексы всех строк, идущих после удаленной, смещаются на один вниз.
  2. Итератор цикла, не «зная» о том, что таблица изменилась, просто переходит к следующему индексу.
  3. Из-за смещения индексов, одна или несколько строк оказываются «пропущенными» и не проверяются условием.

В результате цикл отрабатывает некорректно, и часть «лишних» строк остается в таблице. Кроме того, использование вложенных циклов для поиска и удаления часто приводит к квадратичной сложности алгоритма, что существенно замедляет работу обработки при большом объеме данных.

Способ 1: Сбор строк для удаления в отдельный массив

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

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


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

Для Каждого Строка Из МассивДляУдаления Цикл
    ТаблицаДанных.Удалить(Строка);
КонецЦикла;

Этот метод гарантирует, что мы не «сбиваем» итератор в процессе обхода, и каждая строка будет корректно проверена.

Способ 2: Обход таблицы в обратном порядке

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

Реализуем это следующим образом:


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

Этот метод считается классическим приемом для «очистки» коллекций в 1С без использования вспомогательных объектов.

Способ 3: Создание новой таблицы (копирование)

Часто самым эффективным методом с точки зрения производительности является создание новой ТаблицаЗначений, в которую мы переносим только те данные, которые должны остаться. Это позволяет избежать множественных операций удаления, которые могут быть «дорогими» для процессора, если строк тысячи.

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


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

Рекомендации по оптимизации

При работе с большими объемами данных помните о следующих правилах:

Теперь, когда мы проанализировали причины возникновения ошибки и разобрали основные способы её устранения, вы сможете писать более надежный и производительный код. Всегда выбирайте способ, исходя из размера вашей таблицы и сложности критериев отбора!

← На главную