К статье
Практический материал

Разработка и Конфигурация · 11 мин

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

Как удалить строку таблицы значений в 1С: методы Удалить, НайтиСтроки, цикл с конца, обработка коллекций. Примеры кода, типичные ошибки и проверка результата.

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

Главная ловушка при работе с удалением — изменение коллекции во время её перебора. Если удалять строки внутри обычного цикла «Для Каждого», индексы сдвигаются, часть строк пропускается, а в худшем случае код падает с ошибкой. Ниже разобраны безопасные приёмы: метод Удалить(), перебор с конца, работа через НайтиСтроки() и полная очистка таблицы.

Все примеры приведены на встроенном языке 1С и работают как на сервере, так и на клиенте (с учётом ограничений тонкого клиента). Код можно вставить в модуль обработки или формы и адаптировать под свои имена колонок.

Основной метод Удалить(): по строке и по индексу

Метод Удалить() у коллекции строк таблицы значений принимает либо саму строку (объект типа СтрокаТаблицыЗначений), либо её индекс — целое число от 0 до КоличествоСтрок - 1. Оба варианта равнозначны по результату, но различаются по удобству в разных сценариях.

bsl
// Удаление по объекту строки
Строка = ТаблицаЗначений[0];
ТаблицаЗначений.Удалить(Строка);

// Удаление по индексу — та же операция
ТаблицаЗначений.Удалить(0);

Если передать индекс за пределами диапазона, платформа выдаст ошибку «Индекс находится за границами массива». Поэтому перед удалением по индексу полезно проверять количество строк, особенно если индекс вычисляется динамически. Удаление по объекту строки безопаснее: пока вы держите ссылку на строку, она однозначно идентифицирует элемент коллекции.

После удаления строки индексы всех последующих строк уменьшаются на единицу. Это ключевое свойство, из-за которого возникают ошибки при удалении в прямом цикле: строка, которая была пятой, после удаления четвёртой становится четвёртой, и при следующем шаге цикла она будет пропущена.

Удаление строк по условию через НайтиСтроки()

Самый надёжный способ удалить строки по критерию — метод НайтиСтроки(). Он возвращает массив строк, удовлетворяющих отбору, и этот массив независим от таблицы: можно спокойно удалять найденные строки, не опасаясь сдвига индексов внутри перебора.

bsl
Отбор = Новый Структура("Количество", 0);
НайденныеСтроки = ТаблицаЗначений.НайтиСтроки(Отбор);

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

Структура отбора может содержать несколько полей — тогда отбираются строки, где совпадают все указанные значения одновременно (условие И). Например, НайтиСтроки(Новый Структура("Склад, Отменён", СкладОсновной, Истина)) вернёт только отменённые строки конкретного склада.

Ограничение метода: сравнение идёт только на точное равенство. Условия вида «больше», «меньше», «содержит подстроку» через НайтиСтроки() не выразить — для них нужен перебор с проверкой внутри цикла, который описан в следующем разделе.

Удаление в цикле: почему перебирать нужно с конца

Когда условие сложное — сравнения, вычисления, проверка нескольких полей по логике «ИЛИ» — приходится перебирать таблицу в цикле. Прямой перебор «Для Каждого» с удалением внутри приводит к пропуску строк: после удаления текущей строки коллекция сжимается, а итератор переходит к следующей позиции, фактически перепрыгивая через элемент.

Правильный приём — обратный цикл по индексу от последней строки к первой. При удалении сдвигаются только индексы строк, стоящих после удалённой, а они уже обработаны. Строки с меньшими индексами остаются на своих местах, и ни одна не теряется.

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

Альтернатива без обратного перебора — собрать строки-кандидаты в отдельный массив во время прямого цикла, а удалять уже после его завершения. Это чуть более многословно, но наглядно и так же безопасно, как работа с НайтиСтроки().

Типичные ошибки
01
Удаление строк внутри цикла «Для Каждого» — часть строк пропускается из-за сдвига индексов
02
Удаление по индексу без проверки границ — ошибка «Индекс за границами массива» при пустой таблице
03
Отбор в НайтиСтроки со значением другого типа — метод возвращает пустой массив, и строки не удаляются
04
Использование Удалить() там, где нужен Очистить() — цикл по тысячам строк вместо одного вызова

Удаление всех строк и частичная очистка

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

bsl
ТаблицаЗначений.Очистить();
// Колонки сохранены, строк нет:
// ТаблицаЗначений.Количество() = 0
// ТаблицаЗначений.Колонки.Количество() — без изменений

Если требуется удалить и строки, и колонки — например, таблица больше не нужна вовсе — достаточно присвоить переменной новое значение или Неопределено и дать сборщику мусора освободить память. Явного метода «уничтожить таблицу» в платформе нет.

Частная задача — удалить первые N строк или последние N строк. Здесь работает тот же принцип обратного цикла: для удаления первых N строк удаляйте строку с индексом 0 ровно N раз (каждый раз следующая строка сдвигается на её место), для последних N — удаляйте последнюю строку в цикле от конца.

Дубли, свёртка и альтернатива удалению

Удаление дублирующихся строк — отдельный сценарий. Вместо ручного поиска повторов часто выгоднее использовать метод Свернуть(): он группирует строки по указанным колонкам и суммирует числовые поля. Если суммировать нечего, создайте вспомогательную числовую колонку со значением 1 — после свёртки получите уникальные комбинации значений.

Ещё одна альтернатива удалению — не удалять вовсе, а сформировать новую таблицу только с нужными строками. Это удобно, когда условие сложное, а исходную таблицу нужно сохранить: например, она пришла как параметр в функцию, и менять её нежелательно.

Способы убрать строки из таблицы

Удалить() по строке или индексу

Одна известная строка. Просто, но требует контроля индексов при массовом удалении

НайтиСтроки() + Удалить()

Удаление по точному равенству полей. Безопасно, но не поддерживает условия «больше/меньше»

Обратный цикл по индексу

Любые сложные условия. Универсально, но кода больше

Свернуть()

Устранение дублей с группировкой. Меняет структуру данных — суммирует числовые колонки

Новая таблица с отбором

Когда исходную таблицу нельзя изменять. Требует дополнительной памяти

Таблица значений как реквизит формы

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

Если строка удаляется по действию пользователя — например, по кнопке «Удалить строку» — берите текущую строку из элемента формы через Элементы.ИмяТаблицы.ТекущиеДанные или ТекущаяСтрока. Удаление по ТекущаяСтрока (это индекс) требует проверки, что строка вообще выбрана: если пользователь не установил курсор, значение будет Неопределено.

bsl
&НаКлиенте
Процедура УдалитьТекущуюСтроку(Команда)
    ТекущиеДанные = Элементы.Товары.ТекущиеДанные;
    Если ТекущиеДанные = Неопределено Тогда
        Возврат;
    КонецЕсли;
    Товары.Удалить(Товары.Индекс(ТекущиеДанные));
КонецПроцедуры

Обратите внимание: для реквизита формы удаление по объекту строки напрямую может быть недоступно в некоторых контекстах, поэтому надёжный шаблон — получить индекс через метод Индекс() и удалить по нему, как в примере выше.

Проверка результата и производительность

После удаления убедитесь, что результат соответствует ожиданию: сравните количество строк до и после, при отладке выведите оставшиеся значения ключевых колонок. Для массовых операций полезно зафиксировать счётчик удалённых строк — это помогает заметить, что отбор сработал не так, как задумано (например, удалено 0 строк из-за несовпадения типов).

Контрольные точки

Как проверить результат

Количество строк после удаления
Норма

Уменьшилось ровно на число строк, попадающих под условие

Тревожный признак

Не изменилось (отбор ничего не нашёл) или уменьшилось сильнее ожидаемого

Оставшиеся данные
Норма

Строки, не подпадающие под условие, на месте и не искажены

Тревожный признак

Пропали строки, которые должны были остаться — признак удаления в прямом цикле

Структура таблицы
Норма

Колонки и их типы сохранены после Очистить()

Тревожный признак

Таблица стала Неопределено — переменную перезаписали

По производительности: удаление одной строки — операция быстрая, но удаление тысяч строк по одной в цикле с поиском индекса может быть заметным на больших таблицах. Если нужно оставить небольшую часть строк, эффективнее создать новую таблицу и скопировать в неё нужное, чем удалять 90% содержимого по одной строке. Для отборов на этапе получения данных вообще предпочтительнее отфильтровать записи в запросе через ГДЕ — тогда лишние строки просто не попадут в таблицу.

Итог

Что важно запомнить

Одну строку удаляют методом Удалить() по объекту или индексу, по условию — через НайтиСтроки() или обратный цикл по индексу, все строки — методом Очистить(). Никогда не удаляйте строки внутри прямого цикла «Для Каждого»: из-за сдвига индексов часть данных будет пропущена.

Частые вопросы

Как удалить строку таблицы значений по номеру?

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

Почему при удалении в цикле пропускаются строки?

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

Как удалить строки, где поле пустое?

Через обратный цикл с проверкой Не ЗначениеЗаполнено(Строка.ИмяПоля). НайтиСтроки() здесь подходит только частично: пустая ссылка и пустая строка — разные пустые значения, и одним отбором все варианты «пустоты» не охватить. Проверка в цикле надёжнее.

Чем отличается Очистить() от удаления всех строк в цикле?

Результат одинаков — таблица без строк, но с сохранёнными колонками. Разница в скорости и читаемости: Очистить() выполняется одним вызовом и сразу показывает намерение. Цикл из тысяч вызовов Удалить() делает то же самое медленнее и выглядит как ошибка проектирования.

Можно ли отменить удаление строки?

Нет, метод Удалить() необратим: удалённая строка не попадает ни в какую «корзину». Если есть вероятность, что данные понадобятся, перед удалением скопируйте строки в другую таблицу через Добавить() и ЗаполнитьЗначенияСвойств() либо сохраните копию всей таблицы методом Скопировать().

Как удалить дубли строк в таблице значений?

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