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

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

Как объединить два списка значений в 1С

Как объединить два списка значений в 1С: методы Добавить, ЗагрузитьЗначения, работа через массив, удаление дублей. Примеры кода, ошибки и проверка результата.

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

Выбор способа зависит от трёх условий: нужно ли сохранить представления и пометки элементов, допустимы ли дубликаты значений и насколько велик объём данных. Ниже разобраны рабочие варианты с примерами кода, критериями выбора и типичными ошибками.

Что нужно знать о списке значений перед объединением

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

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

Третий нюанс — типы данных. Список может хранить значения разных типов, но если дальше список используется в параметре запроса или в отборе, смешение типов (например, ссылки разных справочников и строки) может привести к ошибкам или неожиданному поведению.

Способ 1. Объединение циклом через метод Добавить()

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

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

Список1.Добавить(Элемент.Значение, Элемент.Представление, Элемент.Пометка);

КонецЦикла;

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

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

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

Способ 2. Объединение через массивы и ЗагрузитьЗначения()

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

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

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

Для Каждого Значение Из Массив2 Цикл

Массив1.Добавить(Значение);

КонецЦикла;

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

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

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

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

Способ 3. Объединение без дубликатов

Частая потребность — получить объединение, где каждое значение встречается один раз (аналог операции «ИЛИ» для множеств). Простейший вариант — проверять наличие значения перед добавлением методом НайтиПоЗначению():

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

Если Список1.НайтиПоЗначению(Элемент.Значение) = Неопределено Тогда

Список1.Добавить(Элемент.Значение, Элемент.Представление, Элемент.Пометка);

КонецЕсли;

КонецЦикла;

У этого подхода есть ограничение по производительности: НайтиПоЗначению() выполняет линейный поиск, и на больших списках (тысячи элементов) объединение замедлится. Для крупных объёмов эффективнее выгрузить всё в таблицу значений и свернуть:

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

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

Для Каждого Элемент Из МассивОбщий Цикл

Строка = Таблица.Добавить();

Строка.Значение = Элемент;

КонецЦикла;

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

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

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

Сравнение способов объединения

Цикл с Добавить()

Сохраняет представления и пометки, простой и читаемый. Не убирает дубликаты, при проверке уникальности медленный на больших списках.

Через массивы и ЗагрузитьЗначения()

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

Через ТаблицуЗначений со свёрткой

Быстро убирает дубликаты на больших объёмах. Кода больше, представления теряются.

Через Соответствие

Автоматическая уникальность ключей, быстрый поиск. Требуется дополнительный перенос в список.

Как выбрать подходящий способ

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

Отдельный случай — объединение списков в запросе. Если оба набора значений формируются запросами к базе, зачастую правильнее объединить их на уровне запроса через ОБЪЕДИНИТЬ или ОБЪЕДИНИТЬ ВСЕ, а не собирать списки в коде. Это быстрее и сразу даёт уникальность (при ОБЪЕДИНИТЬ без ВСЕ).

Маршрут решения

Как выбрать действие

Нужно сохранить представления и пометки элементовИспользуйте цикл с Добавить(), перенося все параметры элемента
Нужны только значения для параметра запросаВыгрузите оба списка в массивы, сложите массивы и передайте в запрос
Дубликаты недопустимы, списки небольшиеДобавляйте с проверкой НайтиПоЗначению()
Дубликаты недопустимы, элементов тысячиВыгрузите в ТаблицуЗначений и выполните Свернуть()
Оба набора данных получаются запросамиОбъедините их в самом запросе через ОБЪЕДИНИТЬ

Проверка результата объединения

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

Для отладки выведите содержимое списка в цикле через Сообщить() или посмотрите его в табло отладчика. Проверьте также типы значений: если в итоговом списке оказались строки вместо ссылок, значит где-то в цепочке значение было преобразовано, например при сериализации или передаче между клиентом и сервером.

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

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

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

Равно сумме размеров исходных списков (без удаления дублей)

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

Меньше или больше ожидаемого — проверьте логику цикла и свёртку

Типы значений элементов
Норма

Сохранены исходные типы (ссылки, числа и т.д.)

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

Значения превратились в строки или Неопределено

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

Совпадают с исходными представлениями

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

Представления пустые или сформированы автоматически там, где нужны исходные

Наличие дубликатов
Норма

Соответствует задуманному: есть или отсутствуют

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

Дубли появились там, где должна быть уникальность

Типичные ошибки и ограничения

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

Вторая ошибка — модификация списка во время перебора его же элементов. Если вы перебираете Список1 и добавляете элементы в него же, цикл может стать бесконечным или пропустить элементы. Всегда добавляйте элементы в другой список либо перебирайте копию.

Третья группа проблем связана с передачей списков между клиентом и сервером в управляемых формах. Список значений сериализуется, и ссылочные значения при некоторых сценариях могут терять связь с контекстом. Если объединение выполняется в клиент-серверном коде, надёжнее выполнять его целиком на сервере.

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

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

Можно ли объединить два списка значений одной командой?

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

Как объединить списки, чтобы порядок элементов сохранился?

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

Чем отличается ОБЪЕДИНИТЬ от ОБЪЕДИНИТЬ ВСЕ в запросе?

ОБЪЕДИНИТЬ убирает дубликаты строк из результата, ОБЪЕДИНИТЬ ВСЕ сохраняет все строки, включая повторы. Если оба набора данных получаются запросами, объединение на уровне запроса обычно эффективнее, чем сборка списков в коде.

Как удалить дубликаты из уже объединённого списка?

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

Почему после объединения пропали представления элементов?

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

Можно ли объединить списки значений разных типов?

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

Итог

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

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