Почему возникают ошибки при удалении строк из коллекции в цикле и как их исправить?

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

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

В чем заключается проблема?

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

Рассмотрим подробнее два проверенных способа решения этой задачи, которые гарантируют корректную работу кода.

Способ 1: Обратный обход коллекции

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

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


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

Преимущества этого способа:

  1. Не требуется создание дополнительных объектов в памяти.
  2. Весь процесс выполняется за один проход по коллекции.
  3. Логика интуитивно понятна и безопасна с точки зрения индексов.

Способ 2: Использование вспомогательного массива

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

Разберем этот алгоритм по шагам:

  1. Создаем пустой массив МассивКУдалению = Новый Массив;.
  2. Проходим по исходной коллекции и при выполнении условия добавляем найденную строку (или индекс) в этот массив.
  3. После завершения основного цикла проходим по МассивКУдалению и удаляем соответствующие объекты из исходной таблицы.

МассивКУдалению = Новый Массив;

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

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

Этот подход особенно удобен, если удаление происходит не по индексу, а по ссылке на объект (строку), так как метод Удалить() коллекции позволяет передать саму строку в качестве параметра.

Важное примечание: работа с результатами запроса

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

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

Применяя данные методы, вы обеспечите стабильность своего кода и избавитесь от ошибок перескакивания через важные данные!

← На главную