Разработка и Конфигурация · 9 мин
Как свернуть список значений в 1С
Как свернуть список значений в 1С: удаление дублей, свёртка таблицы значений методом Свернуть(), группировка в запросе. Примеры кода, ошибки и проверка результата.
Задача свернуть список значений в 1С возникает, когда в коллекции накапливаются повторяющиеся элементы: одни и те же контрагенты, номенклатура или склады попадают в список несколько раз, и перед дальнейшей обработкой нужно оставить только уникальные значения. Встроенного метода «Свернуть» у объекта СписокЗначений нет, поэтому задачу решают обходными путями — через соответствие, таблицу значений или запрос.
Выбор способа зависит от контекста: где живут данные (на клиенте или на сервере), сколько элементов в списке, нужно ли сохранить порядок и представления, и что считать «дубликатом» — совпадение только значения или значения вместе с представлением. Ниже разобраны рабочие варианты с готовым кодом, условиями их применения и типичными ошибками.
Что значит «свернуть» список и когда это нужно
Под свёрткой обычно понимают одну из трёх операций. Первая — удаление дублей: в списке остаётся по одному экземпляру каждого значения. Вторая — группировка с агрегацией, когда значения складываются или считаются (это уже территория таблицы значений). Третья — свёртка в строку, когда список превращают в одну строку с разделителем, например для подстановки в текст письма или параметр отбора.
Типовые сценарии: список выбранных пользователем элементов на форме содержит повторы; результат обхода выборки дал повторяющиеся ссылки; нужно сформировать уникальный перечень документов для пакетной обработки. Во всех случаях логика одинакова — пройти коллекцию и оставить уникальные значения, различается только механизм.
Способ 1: удалить дубли через соответствие
Самый универсальный приём — пройти по списку и использовать Соответствие как фильтр уникальности. Ключом соответствия выступает само значение: если ключ уже есть, элемент пропускается. Соответствие работает быстро даже на больших списках, потому что поиск ключа в нём выполняется за постоянное время, а не перебором.
Функция СвернутьСписокЗначений(ИсходныйСписок)
Результат = Новый СписокЗначений;
Уникальные = Новый Соответствие;
Для Каждого Элемент Из ИсходныйСписок Цикл
Если Уникальные[Элемент.Значение] = Неопределено Тогда
Уникальные.Вставить(Элемент.Значение, Истина);
Результат.Добавить(Элемент.Значение, Элемент.Представление);
КонецЕсли;
КонецЦикла;
Возврат Результат;
КонецФункции
Такой вариант сохраняет порядок первого вхождения каждого значения и представления элементов. Он работает и в тонком, и в веб-клиенте, не требует передачи данных на сервер, если список уже находится на форме. Ограничение: сравнение идёт по значению, поэтому две разные ссылки с одинаковым наименованием будут считаться разными элементами — что обычно и требуется.
Способ 2: свёртка через таблицу значений
Если список находится на сервере или данные уже удобно держать в таблице, используйте штатный метод ТаблицаЗначений.Свернуть(). Он группирует строки по указанным колонкам и опционально суммирует числовые колонки. Для списка значений приём выглядит так: выгрузить значения в таблицу, свернуть, загрузить обратно.
Таблица = Новый ТаблицаЗначений;
Таблица.Колонки.Добавить("Значение");
Для Каждого Элемент Из Список Цикл
Таблица.Добавить().Значение = Элемент.Значение;
КонецЦикла;
Таблица.Свернуть("Значение");
Список.Очистить();
Список.ЗагрузитьЗначения(Таблица.ВыгрузитьКолонку("Значение"));
У метода Свернуть() есть важная особенность: после свёртки в таблице остаются только колонки группировки и суммируемые колонки, все прочие удаляются. Если таблица используется где-то ещё, сворачивайте её копию. Ещё один нюанс — порядок строк после свёртки не гарантированно совпадает с исходным, поэтому при необходимости добавьте сортировку.
Способ 3: группировка в запросе
Если список строится из данных информационной базы, правильнее не сворачивать готовый список, а сразу получить уникальные значения запросом. Для этого используют конструкции РАЗЛИЧНЫЕ или СГРУППИРОВАТЬ ПО. Это самый производительный вариант, потому что группировка выполняется на уровне СУБД и в прикладной код не попадают лишние строки.
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ РАЗЛИЧНЫЕ
| РеализацияТоваровУслуг.Контрагент КАК Контрагент
|ИЗ
| Документ.РеализацияТоваровУслуг КАК РеализацияТоваровУслуг
|ГДЕ
| РеализацияТоваровУслуг.Ссылка В (&СписокДокументов)";
СписокКонтрагентов = Новый СписокЗначений;
СписокКонтрагентов.ЗагрузитьЗначения(
Запрос.Выполнить().Выгрузить().ВыгрузитьКолонку("Контрагент"));
Запросный подход особенно выгоден, когда нужна не просто уникальность, а агрегаты: количество документов по контрагенту, суммы по номенклатуре. В этом случае вместо РАЗЛИЧНЫЕ применяют СГРУППИРОВАТЬ ПО с функциями СУММА, КОЛИЧЕСТВО, МАКСИМУМ. Переносить такую логику в цикл по списку — заведомо более медленное и громоздкое решение.
Сравнение вариантов свёртки
Подходит для списка на клиенте или сервере, сохраняет порядок и представления. Ограничение: только проверка уникальности, без суммирования.
Подходит для серверного кода и когда нужны итоги по числовым колонкам. Ограничение: удаляет лишние колонки и не сохраняет порядок.
Лучший вариант, если данные ещё не выбраны из базы. Ограничение: неприменим к списку, сформированному вручную на форме.
Свёртка списка в строку с разделителем
Отдельная частая задача — «свернуть» список в одну строку, например перечислить номера документов через запятую в сообщении пользователю. Для этого не нужны циклы со склейкой: у списка значений есть косвенный приём через соединение массива, а начиная с современных версий платформы удобно использовать СтрСоединить.
МассивСтрок = Новый Массив;
Для Каждого Элемент Из Список Цикл
МассивСтрок.Добавить(Строка(Элемент.Значение));
КонецЦикла;
Результат = СтрСоединить(МассивСтрок, ", ");
Обратите внимание на явное приведение к строке: если значения — ссылки, Строка() вернёт их представление, иначе соединение может завершиться ошибкой преобразования типа. Для длинных списков имеет смысл ограничить вывод первыми несколькими элементами и добавить «и ещё N», чтобы не перегружать сообщение.
Проверка результата и типичные ошибки
После свёртки проверьте три вещи: количество элементов уменьшилось до ожидаемого, порядок соответствует требованиям дальнейшей логики, представления и пометки не потерялись, если они используются. Пометки — частый источник потерь: при переносе значений через ЗагрузитьЗначения пометки сбрасываются, поэтому при необходимости переносите их вручную в цикле.
Ещё одна ошибка — попытка свернуть список значений, заполненный элементами составного типа, где «одинаковые» с точки зрения пользователя значения имеют разные типы (например, строка и число). Определитесь заранее, что является ключом уникальности, и при необходимости нормализуйте значения перед свёрткой.
Как проверить результат
Стало меньше ровно на число дублей
Количество не изменилось — дубли не найдены, проверьте типы значений
Сохранён порядок первых вхождений
Порядок перемешан — вероятно, использована свёртка таблицы без сортировки
Сохранены у всех элементов
Пометки сброшены — переносите их вручную в цикле
Что важно запомнить
Метода Свернуть() у списка значений нет. Для удаления дублей используйте Соответствие, для группировки с итогами — ТаблицаЗначений.Свернуть() на копии данных, а если данные ещё в базе — сразу группируйте запросом. Следите за типами значений, порядком и пометками.
Частые вопросы
Есть ли у списка значений встроенный метод для удаления дублей?
Нет, у объекта СписокЗначений такого метода нет. Ближайшие штатные средства — Свернуть() у таблицы значений и группировка в запросе. Для самого списка дубли убирают вручную через Соответствие или переносом в таблицу.
Как свернуть список значений на управляемой форме без вызова сервера?
Пройдите по списку в клиентской процедуре и соберите новый список через Соответствие — этот объект доступен в тонком и веб-клиенте. Обращения к серверу не потребуется, если все данные уже на форме.
Почему после Свернуть() таблицы значений пропали колонки?
Так устроен метод: после свёртки остаются только колонки, перечисленные в параметрах группировки и суммирования. Чтобы не потерять данные, вызывайте Свернуть() для копии таблицы, полученной методом Скопировать().
Что быстрее: свёртка через соответствие или через запрос?
Если данные уже загружены в список — соответствие быстрее, так как запрос к базе не нужен. Если данные ещё предстоит получить, группировка в запросе выигрывает, потому что лишние строки вообще не передаются в прикладной код.
Как свернуть список, сохранив пометки элементов?
Переносите элементы вручную в цикле: при добавлении в новый список передавайте не только значение и представление, но и пометку через свойство Пометка элемента. Метод ЗагрузитьЗначения пометки не сохраняет.
Можно ли свернуть список значений по представлению, а не по значению?
Да, используйте представление как ключ соответствия вместо значения. Учтите, что тогда два разных значения с одинаковым представлением сольются в один элемент — убедитесь, что это допустимо для вашей задачи.