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