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