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

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

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

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

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

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

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

Почему в массиве появляются дубли и когда их нужно убирать

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

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

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

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

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

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

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

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

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

КонецЦикла;

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

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

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

КонецЦикла;

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

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

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

Ограничение у способа есть: порядок элементов в итоговом массиве не гарантированно совпадает с порядком их первого появления в исходном. Если порядок важен (например, массив этапов обработки), либо сохраняйте его отдельно, либо используйте другой подход.

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

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

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

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

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

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

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

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

КонецЦикла;

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

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

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

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

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

Сравнение вариантов

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

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

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

Подходит, когда данные уже в таблице или нужна явная типизация. Требует больше кода и памяти.

Проход с Найти()

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

Способ 3: проход с проверкой вхождения через Найти()

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

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

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

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

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

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

КонецЕсли;

КонецЦикла;

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

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

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

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

bsl
// Компактный вариант через Соответствие
Соответствие = Новый Соответствие;
Для Каждого Эл Из МассивСДублями Цикл
	Соответствие.Вставить(Эл, Истина);
КонецЦикла;
МассивБезДублей = Новый Массив;
Для Каждого КЗ Из Соответствие Цикл
	МассивБезДублей.Добавить(КЗ.Ключ);
КонецЦикла;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Повторная обработка
Норма

Повторное удаление дублей не меняет размер массива

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

Размер снова уменьшается — дубли остались

Состав значений
Норма

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

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

Часть значений потеряна — проверьте типы элементов

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

Порядок соответствует требованиям логики

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

Порядок нарушен там, где он важен — смените способ

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

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

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

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

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

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

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

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

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

Да, если данные ещё не выгружены из запроса, используйте в тексте запроса конструкцию ВЫБРАТЬ РАЗЛИЧНЫЕ — она вернёт только уникальные строки. Это предпочтительный вариант, потому что сокращает объём передаваемых данных и снимает необходимость постобработки в коде.

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

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

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

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

Что быстрее на большом массиве: Соответствие или Найти()?

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

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

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

Можно ли удалить дубли в колонке таблицы значений без создания массива?

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