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