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

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

Как свернуть список значений в 1С

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

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

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

Что значит «свернуть» список и когда это нужно

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

Типовые сценарии: список выбранных пользователем элементов на форме содержит повторы; результат обхода выборки дал повторяющиеся ссылки; нужно сформировать уникальный перечень документов для пакетной обработки. Во всех случаях логика одинакова — пройти коллекцию и оставить уникальные значения, различается только механизм.

Способ 1: удалить дубли через соответствие

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

Функция СвернутьСписокЗначений(ИсходныйСписок)

Результат = Новый СписокЗначений;

Уникальные = Новый Соответствие;

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

Если Уникальные[Элемент.Значение] = Неопределено Тогда

Уникальные.Вставить(Элемент.Значение, Истина);

Результат.Добавить(Элемент.Значение, Элемент.Представление);

КонецЕсли;

КонецЦикла;

Возврат Результат;

КонецФункции

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

Способ 2: свёртка через таблицу значений

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

Таблица = Новый ТаблицаЗначений;

Таблица.Колонки.Добавить("Значение");

Для Каждого Элемент Из Список Цикл

Таблица.Добавить().Значение = Элемент.Значение;

КонецЦикла;

Таблица.Свернуть("Значение");

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

Список.ЗагрузитьЗначения(Таблица.ВыгрузитьКолонку("Значение"));

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

Способ 3: группировка в запросе

Если список строится из данных информационной базы, правильнее не сворачивать готовый список, а сразу получить уникальные значения запросом. Для этого используют конструкции РАЗЛИЧНЫЕ или СГРУППИРОВАТЬ ПО. Это самый производительный вариант, потому что группировка выполняется на уровне СУБД и в прикладной код не попадают лишние строки.

Запрос = Новый Запрос;

Запрос.Текст =

"ВЫБРАТЬ РАЗЛИЧНЫЕ

| РеализацияТоваровУслуг.Контрагент КАК Контрагент

|ИЗ

| Документ.РеализацияТоваровУслуг КАК РеализацияТоваровУслуг

|ГДЕ

| РеализацияТоваровУслуг.Ссылка В (&СписокДокументов)";

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

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

Запрос.Выполнить().Выгрузить().ВыгрузитьКолонку("Контрагент"));

Запросный подход особенно выгоден, когда нужна не просто уникальность, а агрегаты: количество документов по контрагенту, суммы по номенклатуре. В этом случае вместо РАЗЛИЧНЫЕ применяют СГРУППИРОВАТЬ ПО с функциями СУММА, КОЛИЧЕСТВО, МАКСИМУМ. Переносить такую логику в цикл по списку — заведомо более медленное и громоздкое решение.

Сравнение вариантов свёртки

Соответствие

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

ТаблицаЗначений.Свернуть()

Подходит для серверного кода и когда нужны итоги по числовым колонкам. Ограничение: удаляет лишние колонки и не сохраняет порядок.

Запрос с РАЗЛИЧНЫЕ / СГРУППИРОВАТЬ ПО

Лучший вариант, если данные ещё не выбраны из базы. Ограничение: неприменим к списку, сформированному вручную на форме.

Свёртка списка в строку с разделителем

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

МассивСтрок = Новый Массив;

Для Каждого Элемент Из Список Цикл

МассивСтрок.Добавить(Строка(Элемент.Значение));

КонецЦикла;

Результат = СтрСоединить(МассивСтрок, ", ");

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

Проверка результата и типичные ошибки

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

Типичные ошибки
01
Поиск дублей методом НайтиПоЗначению внутри цикла — на больших списках это квадратичная сложность и заметные тормоза; используйте Соответствие.
02
Свёртка исходной таблицы вместо копии — после Свернуть() пропадают колонки, и последующий код падает.
03
Смешение в списке ссылок и строк — дубли не находятся, потому что сравниваются разные типы.
04
Потеря пометок и представлений при перезагрузке списка через ЗагрузитьЗначения — интерфейс выбора перестаёт работать как раньше.

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

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

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

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

Стало меньше ровно на число дублей

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

Количество не изменилось — дубли не найдены, проверьте типы значений

Порядок элементов
Норма

Сохранён порядок первых вхождений

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

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

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

Сохранены у всех элементов

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

Пометки сброшены — переносите их вручную в цикле

Итог

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

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

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

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

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

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

Пройдите по списку в клиентской процедуре и соберите новый список через Соответствие — этот объект доступен в тонком и веб-клиенте. Обращения к серверу не потребуется, если все данные уже на форме.

Почему после Свернуть() таблицы значений пропали колонки?

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

Что быстрее: свёртка через соответствие или через запрос?

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

Как свернуть список, сохранив пометки элементов?

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

Можно ли свернуть список значений по представлению, а не по значению?

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