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

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

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

Анализ типичных ошибок при удалении строк

Рассмотрим ситуацию, с которой столкнулся автор темы. В его исходном коде было две критические проблемы. Проанализируем их, чтобы никогда не повторять в своей практике.

Ошибка №1: Логика проверки на пустоту. Автор использовал конструкцию Если НЕ ТекСтрока <> Неопределено. Разберем, что здесь не так. Во-первых, при обходе коллекции через цикл Для каждого переменная ТекСтрока всегда содержит объект строки таблицы, она в принципе не может быть Неопределено в теле цикла. Во-вторых, двойное отрицание НЕ <> (не не равно) превращается в «равно». Таким образом, условие буквально звучало как «Если строка равна Неопределено», что всегда ложно.

Ошибка №2: Удаление внутри прямого цикла. Это фундаментальная проблема. Когда мы используем Для каждого или цикл по индексу От 0 До Количество - 1, платформа «запоминает» последовательность строк. Как только мы вызываем метод Удалить(), индексы всех последующих строк сдвигаются на единицу вверх. В результате итератор цикла «перепрыгивает» через следующую строку, и она остается необработанной.

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

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

Этот метод считается наиболее читаемым и безопасным. Мы разделяем процесс на два этапа: сначала находим все строки, подлежащие удалению, и складываем их в массив, а затем удаляем их из таблицы.

Рассмотрим реализацию этого метода на примере удаления строк, где не заполнена колонка Номенклатура:


// Создаем массив для хранения ссылок на удаляемые строки
УдаляемыеСтроки = Новый Массив;

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

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

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

Способ №2: Обратный цикл (удаление с конца)

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

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


ВсегоСтрок = Корзина.Количество();

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

Обратите внимание, что мы используем конструкцию Корзина.Удалить(Индекс). Это самый быстрый способ удаления, так как поиск по индексу в коллекции выполняется мгновенно.

Способ №3: Проверка на пустоту через метод НайтиСтроки

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

Рассмотрим пример кода для серверной части:


ПараметрыОтбора = Новый Структура;
ПараметрыОтбора.Вставить("Номенклатура", Справочники.Номенклатура.ПустаяСсылка());

// Получаем массив строк, соответствующих условию
НайденныеСтроки = Корзина.НайтиСтроки(ПараметрыОтбора);

Для Каждого СтрокаДляУдаления Из НайденныеСтроки Цикл
    Корзина.Удалить(СтрокаДляУдаления);
КонецЦикла;

Нюансы работы на клиенте (&НаКлиенте)

В тексте форума автор работает в процедуре &НаКлиенте. Важно понимать, что в управляемых формах реквизиты с типом «Список товаров» или «Корзина» на клиенте представлены типом ДанныеФормыКоллекция. У этого объекта есть свои особенности:

  1. Метод НайтиСтроки() на клиенте не принимает структуру отбора. Он ищет только по совпадению значения во всех колонках сразу. Поэтому для точечного удаления по условию лучше использовать Способ №1 (Массив) или Способ №2 (Обратный цикл).
  2. Если таблица очень большая (тысячи строк), операции на клиенте могут подтормаживать. В этом случае правильнее передать данные на сервер, обработать их там и вернуть результат.
  3. Вместо Не ТекСтрока <> Неопределено всегда используйте универсальную функцию ЗначениеЗаполнено(ТекСтрока.ИмяРеквизита). Она корректно работает и со строками, и со ссылками, и с числами.

Рекомендация по проверке ссылочных типов

Проанализируем еще один важный момент: что считается «пустой» строкой? Если в колонке хранится ссылка на справочник, то ЗначениеЗаполнено вернет Ложь, если там находится «Пустая ссылка». Однако иногда разработчики предпочитают явное сравнение:

Если ТекСтрока.Номенклатура = ПредопределенноеЗначение("Справочник.Номенклатура.ПустаяСсылка") Тогда...

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

Заключение

Подведем итог. Чтобы успешно удалить строки из таблицы по условию, мы должны придерживаться трех правил:

  1. Никогда не удалять строки внутри обычного цикла Для каждого.
  2. Для удаления «на месте» использовать обратный цикл по индексу (от Количество() - 1 до 0).
  3. Для сложной логики использовать предварительный сбор удаляемых объектов в массив.

Соблюдение этих простых правил сделает ваш код стабильным, а работу интерфейса — предсказуемой для пользователя.

← На главную