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

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

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

Использование встроенного метода Уникальные

Начиная с определенных версий платформы 1С:Предприятие 8, разработчикам стал доступен мощный встроенный метод, который позволяет решить задачу удаления дубликатов в одну строку кода. Метод Уникальные создает новую таблицу значений, в которую попадают только уникальные строки из исходной таблицы. Это наиболее предпочтительный способ с точки зрения читаемости кода и скорости выполнения.

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

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

⚠️ Внимание: Метод Уникальные доступен не во всех релизах платформы. Если вы поддерживаете старые конфигурации на версии 8.2 или ранних сборках 8.3, этот метод может быть недоступен, и потребуется использовать альтернативные способы.
💡

Всегда проверяйте доступность метода Уникальные в вашей версии платформы перед внедрением его в промышленный код. Для старых версий используйте алгоритмы с сортировкой.

Рассмотрим пример использования. Предположим, у нас есть таблица со списком номенклатуры, где некоторые товары повторяются. Нам нужно оставить только уникальные наименования.

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

ТаблицаДанных.Колонки.Добавить("Номенклатура");

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

// Заполняем данными с дублями

Строка = ТаблицаДанных.Добавить;

Строка.Номенклатура ="Товар А";

Строка = ТаблицаДанных.Добавить;

Строка.Номенклатура ="Товар А"; // Дубль

Строка = ТаблицаДанных.Добавить;

Строка.Номенклатура ="Товар Б";

// Получаем таблицу без дублей

ТаблицаБезДублей = ТаблицаДанных.Уникальные;

Алгоритм удаления через Сортировку и циклы

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

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

Ключевым моментом здесь является правильное сравнение значений. Для типов данных, таких как Строка или Число, сравнение тривиально. Однако при работе со ссылками на объекты или составными типами данных необходимо быть внимательным, чтобы не получить ошибку типов.

Почему сортировка ускоряет поиск дублей?

Без сортировки для проверки уникальности каждой строки пришлось бы сравнивать её со всеми остальными строками таблицы, что дает сложность алгоритма O(N^2). Сортировка позволяет сравнивать строку только с одной соседней, снижая сложность до O(N*logN) за счет сортировки и O(N) за счет прохода.

Реализация такого алгоритма обычно выглядит следующим образом:

ТаблицаДанных.Сортировать("Номенклатура Возр");

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

НоваяТаблица.Колонки.Скопировать(ТаблицаДанных.Колонки);

ПредыдущееЗначение = Неопределено;

Для Каждого СтрокаТаблицы Из ТаблицаДанных Цикл

ТекущееЗначение = СтрокаТаблицы.Номенклатура;

Если ТекущееЗначение <> ПредыдущееЗначение Тогда

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

НоваяСтрока.Заполнить(СтрокаТаблицы);

ПредыдущееЗначение = ТекущееЗначение;

КонецЕсли;

КонецЦикла;

Удаление дублей по нескольким колонкам

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

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

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

📊 Какой метод удаления дублей вы используете чаще?
Встроенный метод Уникальные
Цикл с сортировкой
Запрос к временной таблице
Консоль запросов вручную

Пример вызова метода с указанием конкретных колонок:

// Уникальность определяется парой: Контрагент + Договор

ТаблицаРезультат = ИсходнаяТаблица.Уникальные("Контрагент, Договор");

В ручном режиме логика усложняется:

Если (Строка.Контрагент = ПредКонтрагент) И (Строка.Договор = ПредДоговор) Тогда

// Это дубль, пропускаем

Иначе

// Уникальная запись

КонецЕсли;

Оптимизация через объект Запрос

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

Суть метода заключается в том, чтобы загрузить данные из ТаблицыЗначений во временную таблицу запроса, а затем выполнить выборку с использованием оператора РАЗЛИЧНЫЕ (DISTINCT) или группировки ПО. СУБД (SQL Server, PostgreSQL, Oracle) справляется с такими задачами намного быстрее, чем встроенный интерпретатор 1С.

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

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

Пример реализации через запрос:

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

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

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

| ВТ.Номенклатура,

| ВТ.Количество

|ПОМЕСТИТЬ ВТ ИЗ

| &ТаблицаДанных КАК ТаблицаДанных

|КАК ВТ";

Запрос.УстановитьПараметр("ТаблицаДанных", ТаблицаДанных);

Результат = Запрос.Выполнить;

ТаблицаБезДублей = Результат.Выгрузить;

Сравнение производительности методов

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

Метод с использованием встроенной функции Уникальные обычно показывает наилучшие результаты благодаря нативной реализации на C++. Алгоритм с сортировкой и циклом работает медленнее из-за накладных расходов на интерпретацию кода 1С в каждом шаге цикла. Запрос выигрывает на больших объемах, но проигрывает на малых из-за накладных расходов на подготовку и выполнение запроса.

Метод обработки Объем данных (строк) Скорость работы Сложность кода
Уникальные До 100 000 Высокая Низкая
Сортировка + Цикл До 10 000 Средняя Средняя
Запрос (РАЗЛИЧНЫЕ) От 50 000 и выше Очень высокая Высокая
Вложенные циклы До 1 000 Низкая Высокая
💡

Для малых объемов данных (до 5-10 тысяч строк) разница в скорости между методами незаметна для пользователя. Оптимизация критична только при больших объемах.

Типичные ошибки при удалении дубликатов

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

Еще одна распространенная ошибка связана с учетом регистра символов в строковых полях. Для платформы 1С строки"Товар" и"товар" — это разные значения. Если бизнес-требование подразумевает, что это один и тот же товар, необходимо предварительно приводить строки к единому регистру с помощью функции СтрЗаменить или сравнивать их через Сравнить(..., РежимСравненияСтроки.БезУчетаРегистра).

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

⚠️ Внимание: Никогда не удаляйте строки из таблицы значений методом Удалить внутри цикла перебора Для Каждого. Это приведет к ошибке"Коллекция изменена". Используйте метод создания новой таблицы или цикл с индексом в обратном порядке.

☑️ Проверка перед запуском кода

Выполнено: 0 / 1

Часто задаваемые вопросы (FAQ)

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

Напрямую метод Уникальные всегда возвращает новый объект. Чтобы изменить исходную таблицу"на месте", нужно очистить её (Очистить) и добавить строки из результата работы метода, либо использовать цикл с удалением по индексу, что менее производительно.

Как убрать дубли, если значения в колонках отличаются регистром?

Встроенный метод Уникальные учитывает регистр. Для игнорирования регистра необходимо либо предварительно создать временную колонку с приведенным к нижнему регистру значением и делать уникальность по ней, либо использовать запрос с функцией СТРОКА и приведением регистра.

Что делать, если метод Уникальные недоступен в моей версии 1С?

Используйте алгоритм с предварительной сортировкой таблицы (Сортировать) и последующим циклом, сравнивающим текущую строку с предыдущей. Это универсальное решение, работающее на любых версиях платформы 1С:Предприятие.

Влияет ли порядок колонок в таблице на работу метода Уникальные?

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