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