January 10

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

Как обычно очень простая задача. Зачем такое вообще пишу, ведь легко и быстро гуглится, да и языковые модели все это знают и умеют. Но ключевое слово здесь "Правильное"...

Итак имеем таблицу, например табличную часть документа, где главная колонка - номенклатура. Например:

1. Помидор
2. Огурец
3. Редиска
4. Лук
5. Укроп

Допустим хотим удалить Помидор и Редиску. И для этого у нас заполнился МассивИндексовДляУдаления с соответствующими индексами 0 и 2...

Возьмем цикл с прямым обходом:

Для Каждого Индекс из МассивИндексовДляУдаления Цикл
	Таблица.Удалить(Индекс);
КонецЦикла;

При этом удалятся Помидор и Лук. Потому что после удаления строки помидора, строка лука станет третьей (с индексом 2). Эта ошибка известна всем.

Хорошо, тогда давайте сделаем цикл с обратным обходом, ну или проще, отсортируем наш массив индексов по убыванию:

Список = Новый СписокЗначений;
Список.ЗагрузитьЗначения(МассивИндексовДляУдаления);
Список.СортироватьПоЗначению(НаправлениеСортировки.Убыв);
МассивИндексовДляУдаления = Список.ВыгрузитьЗначения();
Для Каждого Индекс из МассивИндексовДляУдаления Цикл
	Таблица.Удалить(Индекс);
КонецЦикла;

Удалились Помидор и Редиска. Все работает, все отлично. Но давайте порассуждаем дальше. Зачем нам удалять строки? Вероятно срабатывает какая-то проверка, которая по какому-то условию находит лишнее и заполняет массив для удаления. А если мы потом добавили еще одну проверку. И какая-то строка была настолько отвратительной, что не прошла обе проверки и в итоге в массив для удаления ее индекс добавится дважды. Ведь мы же обязательно забудем проконтролировать дубли :-) Как сработает наш код, если попробовать дважды удалить Редиску? А удалятся Редиска и Лук. Без какой-либо сигнализации об ошибке. И всплывет это счастье вовсе не на тестах, а уже в эксплуатации когда успеет много чего испортить.

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

Для Каждого СтрокаТаблицы из МассивСтрокДляУдаления Цикл
	Таблица.Удалить(СтрокаТаблицы);
КонецЦикла;

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

Ну то есть, этот конкретный пример подталкивает нас к использованию двух фундаментальных принципов:

Не нужно делать сложно, если можно сделать просто

Не нужно использовать потенциально опасные приемы, даже если это разрешено

←39 | заметка 40