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

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

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

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

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

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

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

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

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

Готовый код функции:

Функция УбратьДубли(Массив)

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

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

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

КонецЦикла;

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

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

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

КонецЦикла;

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

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

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

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

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

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

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

Если Уникальные[Элемент] = Неопределено Тогда

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

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

КонецЕсли;

КонецЦикла;

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

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

Способ 2: свёртка через таблицу значений

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

Функция УбратьДублиЧерезТЗ(Массив)

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

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

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

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

КонецЦикла;

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

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

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

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

Способ 3: перебор с методом Найти()

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

Функция УбратьДублиПростой(Массив)

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

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

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

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

КонецЕсли;

КонецЦикла;

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

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

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

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

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

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

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

Подходит, если данные дальше идут в запрос или таблицу. Избыточен, если нужен только чистый массив.

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

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

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

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

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

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

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

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

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

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

Простой способ проверки — сравнить количество элементов до и после и вывести результат в отладке:

Было = Массив.Количество();

Массив = УбратьДубли(Массив);

Сообщить("Было: " + Было + ", стало: " + Массив.Количество());

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

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

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

После обработки элементов не больше, чем было

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

Элементов стало больше или результат пуст при непустом входе

Пустой входной массив
Норма

Возвращается пустой массив без ошибки

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

Ошибка обращения к элементу или Неопределено

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

Порядок сохранён, если это требовалось

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

Элементы перемешаны при использовании простого соответствия

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

Все элементы результата сохранили исходный тип

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

Ссылки превратились в строки или потеряли тип после свёртки

Частые ошибки и ограничения

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

Вторая типичная проблема — сравнение значений разных типов. Строка "00123" и число 123 — разные значения, и соответствие посчитает их разными элементами. Если дубли могут отличаться типом, приведите элементы к единому виду перед обработкой. То же касается строк с лишними пробелами: имеет смысл применить СокрЛП() и, при необходимости, приведение регистра.

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

Типичные ошибки
01
{'name': 'Удаление элементов в цикле по тому же массиву', 'text': 'Индексы смещаются, часть элементов пропускается. Собирайте новый массив или обходите с конца.'}
02
{'name': 'Структуры как ключи соответствия', 'text': 'Структуры не сравниваются по содержимому, дубли остаются. Используйте ключевое поле структуры.'}
03
{'name': 'Игнорирование типов и пробелов', 'text': "Строка '123' и число 123 считаются разными. Приводите значения к единому виду через СокрЛП() и явное преобразование."}
04
{'name': 'Найти() на большом массиве', 'text': 'Квадратичная сложность — обработка тысяч элементов заметно тормозит. Переходите на соответствие.'}

FAQ

Можно ли удалить дубли из массива запросом?

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

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

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

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

Перед добавлением в соответствие приведите строки к одному регистру через ВРег() или НРег() и уберите пробелы через СокрЛП(). В результат можно складывать либо нормализованное значение, либо первое встреченное исходное, если важно сохранить написание.

Что быстрее: соответствие или таблица значений со свёрткой?

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

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

Напрямую — никак: структуры не сравниваются по значению. Выберите поле-идентификатор (ссылку, код, номер), стройте соответствие по этому полю, а саму структуру сохраняйте в значении соответствия. Затем соберите массив из значений соответствия.

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

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

Итог

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

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