Форум 1С
Программистам, бухгалтерам, администраторам, пользователям
Задай вопрос - получи решение проблемы
22 мая 2022, 10:04

Как удалить элементы коллекции?

Автор MuI_I_Ika, 01 дек 2013, 23:53

0 Пользователей и 1 гость просматривают эту тему.

MuI_I_Ika


Очень часто встречается задача, когда нужно удалить по определенному условию элементы какой-либо коллекции (таблицы значений, массива, списка значений). Разберем пример с таблицей значений.


Первое что приходит обычно в голову - это перебрать коллекцию циклом, и при соблюдении условия удалить элемент методом


Удалить();
Однако, такой подход зачастую сопряжен с определенными трудностями. Ну например, для обхода коллекции вы решили использовать цикл:
Для Каждого Элемент из ТаблицаЗначений Цикл


КонецЦикла;

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


Если представить схематически то получаются две картины до удаления и после удаления:


1          1
2          2 (был 3)
3          3 (был 4)
4


Произошло удаление 2-го элемента. Элементы 3 и 4 сместились в позиции 2 и 3. А программа уже обработала 2-ой элемент и будет обращаться к 3-му.


Если же удалить 3-ий элемент, то программа попытается обратиться к 4-му и возникнет ошибка.


Такая же проблема нас ожидает при использовании цикла


Для к = 0 по ТаблицаЗначений.Количество()-1 Цикл


КонецЦикла;

Дело в том, что для оптимизации производительности количество элементов коллекции вычисляется один раз в начале выполнения цикла, и в дальнейшем уже не пересчитывается. Соответственно и получаем проблему такую же как и в первом случае.


Чтобы избежать подобных проблем можно использовать промежуточный массив, в который вы будете записывать элементы для удаления. Удаление же элементов производить в отдельном цикле.


Вот как будет выглядеть код:


     НайденныеСсылки = НайтиПоСсылкам(МассивСсылок);

//почистим от метаданных исключений
МассивНаУдаление = Новый Массив;


Для каждого Элемент из НайденныеСсылки Цикл

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

КонецЦикла;

Для каждого Элемент из МассивНаУдаление Цикл

НайденныеСсылки.Удалить(Элемент);

КонецЦикла;



Второй вариант удаления строк по условию - это перебор коллекции (в данном случае таблицы значений) с конца. То есть сначала вы обрабатываете самый последний элемент, а конце самый первый. Таким образом программа не собъется со счету, если вы удалите один из элементов посередине, поскольку она будет переходить к элементам с меньшим индексом.


Пример кода:


Для Индекс = -ТаблицаЗначений.Количество()+1 По 0 Цикл

Если ТаблицаЗначений[-Индекс].Количество = 0 Тогда
ТаблицаЗначений.Удалить(-Индекс);
КонецЕсли;

КонецЦикла;



Отмечу, что 1С не поддерживает в цикле Для По переход от большего элемента к меньшему, поэтому здесь применена небольшая хитрость - использование отрицательных чисел.


Третий вариант - использование цикла Пока. Пример кода:


Индекс = ТаблицаКонтрагентов.Количество() - 1;
Пока Индекс >= 0 Цикл
Если ТаблицаКонтрагентов[Индекс].СуммаЗадолженности = 0 Тогда
ТаблицаКонтрагентов.Удалить(Индекс);
КонецЕсли;

Индекс = Индекс - 1;


КонецЦикла;

Похожие темы (1)

Рейтинг@Mail.ru Rambler's Top100

Поиск