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

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

Как убрать дубли в массиве 1С

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

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

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

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

Способ 1. Удаление дублей через Соответствие

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

Функция УбратьДублиЧерезСоответствие(ИсходныйМассив)

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

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

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

КонецЦикла;

Результат = Новый Массив;

Для Каждого КлючЗначение Из Уникальные Цикл

Результат.Добавить(КлючЗначение.Ключ);

КонецЦикла;

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

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

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

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

1c
Уникальные = Новый Соответствие;
Для Каждого Элемент Из Массив Цикл
    Уникальные.Вставить(Элемент, Истина);
КонецЦикла;

Способ 2. Таблица значений и метод Свернуть

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

Функция УбратьДублиЧерезСвернуть(ИсходныйМассив)

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

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

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

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

КонецЦикла;

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

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

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

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

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

Способ 3. Уникальные значения запросом

Если массив формируется из данных информационной базы или его можно передать в запрос как параметр, дубли логично устранить на уровне СУБД. Запрос с группировкой или с ключевым словом «РАЗЛИЧНЫЕ» вернёт только уникальные значения, и перебор в коде вообще не понадобится.

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

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

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

| Товары.Номенклатура КАК Номенклатура

|ИЗ

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

|ГДЕ

| Товары.Ссылка = &Ссылка";

Запрос.УстановитьПараметр("Ссылка", ДокументСсылка);

МассивУникальных = Запрос.Выполнить().Выгрузить().ВыгрузитьКолонку("Номенклатура");

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

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

Способ 4. Перебор с проверкой через Найти

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

Результат = Новый Массив;

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

Если Результат.Найти(Элемент) = Неопределено Тогда

Результат.Добавить(Элемент);

КонецЕсли;

КонецЦикла;

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

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

Сравнение способов

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

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

Таблица значений + Свернуть

Универсальный, поддерживает свёртку по нескольким полям. Медленнее соответствия на простых данных.

Запрос с РАЗЛИЧНЫЕ

Оптимален, когда данные и так берутся из базы. Лишний, если массив уже сформирован в памяти.

Перебор с Найти

Сохраняет порядок, простой код. Тормозит на больших массивах из-за линейного поиска.

Как выбрать способ под свою задачу

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

Если массив ещё только формируется из базы, не создавайте дубли вовсе: сразу пишите запрос с «РАЗЛИЧНЫЕ» или группировкой. Это самый чистый вариант, потому что устраняет проблему на этапе получения данных, а не постфактум.

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

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

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

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

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

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

Вторая типичная проблема — регистр и пробелы в строках. «Товар А» и «товар а» для соответствия — разные ключи. Если нужна регистронезависимая уникальность, приводите строки к одному регистру через ВРег или НРег и обрезайте пробелы через СокрЛП до вставки в соответствие.

Типичные ошибки
01
Сравнение смешанных типов: ссылка и её строковое представление считаются разными значениями, дубли остаются
02
Игнорирование регистра и пробелов в строках — «Номенклатура » и «номенклатура» не схлопнутся
03
Ожидание сохранения порядка после Соответствия — порядок ключей не гарантирован
04
Использование Найти в цикле на массиве в десятки тысяч элементов — код работает неприемлемо долго
05
Попытка удалять элементы из исходного массива внутри цикла по нему же — сдвиг индексов и пропуск элементов
Контрольные точки

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

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

Итоговый массив меньше или равен исходному, значения ожидаемые

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

Итоговый массив пустой или больше исходного — ошибка в логике

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

Прогон результата через Соответствие даёт столько же ключей, сколько элементов

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

Ключей меньше — дубли остались

Полнота данных
Норма

Все ожидаемые уникальные значения присутствуют

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

Часть значений потеряна — проверьте приведение типов и СокрЛП

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

Можно ли удалить дубли прямо в исходном массиве, не создавая новый?

Технически можно, перебирая массив по индексам с конца и вызывая Удалить(Индекс) для повторных значений. Но такой код медленнее и чаще приводит к ошибкам со сдвигом индексов. Практичнее сформировать новый массив через соответствие и присвоить его той же переменной.

Как убрать дубли в массиве структур?

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

Сохранится ли порядок элементов после удаления дублей?

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

Что быстрее: соответствие или таблица значений со Свернуть?

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

Как убрать дубли с учётом регистра строк?

Перед вставкой в соответствие приведите строку к единому виду: ВРег(СокрЛП(Значение)). Тогда «Товар», «товар» и « ТОВАР » станут одним ключом. В результирующий массив можно сохранять либо нормализованное значение, либо первый встретившийся исходный вариант — в зависимости от задачи.

Можно ли убрать дубли без программирования, штатными средствами?

Если речь о данных в табличной части или списке, а не о массиве в коде, используйте группировку в отчёте или консоли запросов с РАЗЛИЧНЫЕ. Для поиска дублей элементов справочников в типовых конфигурациях есть обработка «Поиск и удаление дублей», но она работает с объектами базы, а не с массивами в памяти.

Итог

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

Готового метода удаления дублей у массива в 1С нет. Для больших массивов примитивов и ссылок используйте Соответствие, для сложных данных — таблицу значений со Свернуть, для данных из базы — запрос с РАЗЛИЧНЫЕ. Перед обработкой приведите значения к единому типу и регистру, а результат проверьте повторным прогоном через соответствие.