Очистка списка значений в 1С: методы и примеры кода

· 9 мин

Содержание

Полностью очистить список значений в 1С проще всего одной строкой — Список.Очистить();. Этот метод удаляет сразу все элементы коллекции, и переменная остаётся рабочим объектом типа СписокЗначений — её можно заполнять заново.

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

Материал рассчитан на разработчика: все примеры — готовый код, который можно адаптировать под свою задачу. Объект СписокЗначений одинаково доступен на клиенте, на сервере и во внешнем соединении, поэтому приёмы ниже работают в любой процедуре.

Четыре способа очистить список значений

У объекта СписокЗначений нет «секретной» команды — очистка собирается из четырёх приёмов. Выбор зависит от того, нужно убрать всё или часть, и важно ли сохранить ссылку на тот же объект.

1. Полная очистка методом Очистить(). Самый частый случай — удалить все элементы, оставив тот же объект:

Список.Очистить();

После вызова Список.Количество() вернёт 0. Объект тот же, все ссылки на него остаются валидными — это важно, если список передан в другую процедуру или привязан к элементу формы.

2. Пересоздание объекта. Если ссылки на старый список больше не нужны, можно просто завести новый:

Список = Новый СписокЗначений;

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

3. Загрузка пустого массива. Метод ЗагрузитьЗначения() заменяет всё содержимое списка значениями из переданного массива. Передайте пустой — список очистится:

Список.ЗагрузитьЗначения(Новый Массив);

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

4. Удаление одного элемента методом Удалить(). Метод принимает либо индекс, либо сам элемент списка:

Список.Удалить(0);              // по индексу — первый элемент
Список.Удалить(ЭлементСписка);  // по объекту ЭлементСпискаЗначений

Важная деталь про Удалить(): при передаче индекса платформа удаляет элемент на этой позиции, при передаче объекта ЭлементСпискаЗначений — именно этот элемент, даже если в списке есть другие с таким же значением. Это разные сценарии: индекс отвечает на вопрос «убрать N-й по счёту», объект — «убрать вот этот конкретный».

Очистить() работает мгновенно независимо от размера списка. Если задача — именно «убрать всё», не пишите цикл с Удалить() — это и медленнее, и источник ошибок.

Удаление элементов в цикле без ошибок индексов

Когда нужно убрать несколько элементов по порядку, разработчики пишут цикл — и здесь кроется классическая ловушка. После каждого Удалить() элементы сдвигаются, индексы пересчитываются, и проход «сверху вниз» пропускает элементы или вылетает за границу.

Правило: при удалении в цикле всегда идите от конца списка к началу. Тогда сдвиг затрагивает только уже пройденные позиции.

Во встроенном языке 1С у цикла Для нет шага — он всегда увеличивает счётчик на единицу. Поэтому обход в обратном порядке делают через Пока:

Индекс = Список.Количество() - 1;
Пока Индекс >= 0 Цикл
    Список.Удалить(Индекс);
    Индекс = Индекс - 1;
КонецЦикла;

Так каждый шаг удаляет последний элемент, индексы оставшихся не меняются, и список гарантированно опустеет без сбоев.

Нельзя удалять элементы внутри цикла Для Каждого ... Из Список Цикл. Изменение коллекции во время её обхода вызывает ошибку выполнения. Для удаления используйте Пока с индексом.

Та же логика работает и когда удалять надо не все, а первые несколько элементов до какого-то условия: счётчик в Пока даёт полный контроль над тем, сколько и каких позиций убрать, в отличие от «слепого» Очистить().

Если удаляете по объекту, а не по индексу, пригодится НайтиПоЗначению() — он возвращает элемент или Неопределено:

Найденный = Список.НайтиПоЗначению(ИскомоеЗначение);
Если Найденный <> Неопределено Тогда
    Список.Удалить(Найденный);
КонецЕсли;

Проверка на Неопределено обязательна: без неё попытка удалить несуществующий элемент приведёт к ошибке.

Как удалить только часть элементов по условию

Отбор — это удаление не всех элементов, а тех, что подходят под фильтр. Два надёжных подхода.

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

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

Здесь обращение Список[Индекс] эквивалентно Список.Получить(Индекс) и возвращает ЭлементСпискаЗначений с полями Значение, Представление, Пометка, Картинка.

Подход 2. Выгрузка, фильтрация, загрузка. Удобен, когда условие сложное, а дополнительные атрибуты (пометки, картинки) не важны:

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

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

Сравнение способов очистки по задаче:

ЗадачаМетодЧто учесть
Убрать всёОчистить()тот же объект, мгновенно
Заменить содержимоеЗагрузитьЗначения(Массив)теряет пометки/картинки
Убрать один элементУдалить(Индекс) / Удалить(Элемент)проверьте, что элемент есть
Убрать часть по условиюобратный цикл Покаидти от конца к началу
Проверьте себя
Как правильно удалить элементы списка значений в цикле?
Какой метод очищает список, сохраняя тот же объект?

Память и производительность при больших списках

На коротких списках способ очистки роли не играет. На тысячах элементов разница становится заметной.

🔹 Очистить() — самый быстрый путь. Платформа сбрасывает внутренний массив целиком за одну операцию. Время практически не зависит от числа элементов.

🔹 Поэлементное удаление с начала — медленно. Каждый Удалить(0) сдвигает все оставшиеся элементы на позицию влево. На списке из N элементов это даёт квадратичный рост числа операций. Для очистки «всего» так делать не нужно никогда.

🔹 Обратный цикл Пока — быстрый. Удаление последнего элемента не требует сдвига, поэтому обход от конца к началу работает линейно. Его и применяют, когда удалять надо выборочно.

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

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

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

Когда дальше в код идёт заполнение новым набором, не делайте два прохода. Соберите данные в массив и загрузите разом:

Список.ЗагрузитьЗначения(НовыеЗначения);

Этот вызов сам очищает старое содержимое перед загрузкой — дополнительный Очистить() перед ним избыточен.

Очистка списка в разных контекстах: клиент, сервер, форма

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

В обычной переменной. Никаких особенностей: Очистить() в любом контексте &НаКлиенте или &НаСервере.

Когда список — реквизит формы. Изменили на сервере — не забудьте, что клиентская часть формы увидит изменения только после возврата управления на клиент. Если список отображается в элементе формы (например, в поле с типом списка), после очистки иногда нужно принудительно обновить связанный элемент, чтобы пользователь увидел пустой список.

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

Процедура ОчиститьБуфер(СписокДляОчистки)
    СписокДляОчистки.Очистить();
КонецПроцедуры

После вызова ОчиститьБуфер(МойСписок) исходный МойСписок окажется пустым. Если это нежелательно, передавайте копию — Список.Скопировать().

По версиям платформы поведение методов Очистить(), Удалить(), ЗагрузитьЗначения() одинаково: они работают так и в управляемом, и в обычном приложении, номер релиза 1С 8.3 на логику не влияет.

Очистка списка значений в типовых сценариях

Теория закрыта — разберём, как очистка выглядит в реальном коде, где СписокЗначений обычно и встречается.

Сброс буфера перед новым заполнением. Частый шаблон обработчика: собрать данные, обработать, очистить для следующей итерации. Здесь подойдёт Очистить(), потому что объект тот же и дальше наполняется заново:

Для Каждого СтрокаДанных Из Источник Цикл
    Буфер.Очистить();
    ЗаполнитьБуфер(Буфер, СтрокаДанных);
    ОбработатьБуфер(Буфер);
КонецЦикла;

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

Элементы.ПолеОрганизация.СписокВыбора.Очистить();

После этого список выбора заполняют актуальными значениями методом Добавить(). Путь к элементу идёт через коллекцию Элементы управляемой формы.

Удаление дубликатов. Прямого метода нет, но убрать повторы несложно — проверяем каждое значение перед добавлением в чистовой список:

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

Метод ВыгрузитьЗначения() возвращает массив значений — его и передаём в ЗагрузитьЗначения(), заменяя исходное содержимое набором без повторов.

Если порядок и представления критичны, вместо ЗагрузитьЗначения() присвойте очищенному списку элементы вручную через Добавить() с указанием представления и пометки.

Типичные ошибки и как их избежать

Ошибки при очистке списка значений однотипны и легко узнаваемы. Собрал самые частые.

Диагностика: выберите симптом

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

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

Чем `Очистить()` отличается от `Новый СписокЗначений`?
Очистить() опустошает текущий объект, сохраняя все ссылки на него. Новый СписокЗначений создаёт другой объект и записывает его только в текущую переменную — прежний список при этом продолжает жить, если на него кто-то ссылается.
Освобождается ли память сразу после `Очистить()`?
Список перестаёт держать ссылки на свои прежние значения сразу. Но сами значения освободятся только когда на них не останется ни одной ссылки из другого кода — этим занимается сборщик мусора платформы, не мгновенно по вызову.
Можно ли очистить список значений, не зная его размера?
Да. Очистить() не требует знать количество элементов — он убирает всё. Для выборочного удаления размер берётся динамически через Количество() прямо в условии цикла.
Что вернёт `Удалить()`, если элемента нет?
Удаление по несуществующему индексу или по Неопределено вызовет ошибку выполнения. Поэтому результат НайтиПоЗначению() проверяют на Неопределено до вызова Удалить().
Нужно ли очищать список значений перед его повторным заполнением?
Если заполняете методом ЗагрузитьЗначения() — нет, он сам заменяет содержимое. Если добавляете элементы через Добавить() — да, иначе новые данные лягут поверх старых.