Как найти и удалить дублирующиеся значения в табличной части или таблице значений в 1С 7.7?

Программист 1С v7.7 IT и автоматизация бизнеса
← На главную

При обработке данных в 1С 7.7 разработчики часто сталкиваются с необходимостью удалить дублирующиеся строки в табличной части (ТЧ) документа или в объекте ТаблицаЗначений по определенному реквизиту. Использование классического двойного цикла для попарного сравнения всех строк неэффективно и приводит к серьезным задержкам на больших объемах данных. Разберем наиболее быстрые и изящные способы решения этой задачи.

Способ 1. Обход табличной части с конца с использованием СпискаЗначений

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

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

Посмотрим на программный код реализации этого метода:


КолСтрок = КоличествоСтрок();
СЗ = СоздатьОбъект("СписокЗначений");

Пока КолСтрок > 0 Цикл
    ПолучитьСтрокуПоНомеру(КолСтрок);
    Если СЗ.НайтиЗначение(Реквизит) = 0 Тогда
        СЗ.ДобавитьЗначение(Реквизит);
    Иначе
        УдалитьСтроку();
    КонецЕсли;
    КолСтрок = КолСтрок - 1;
КонецЦикла;

Важный момент: метод НайтиЗначение() объекта СписокЗначений выполняет линейный перебор элементов. При обработке очень больших списков (от нескольких тысяч строк) скорость поиска может снижаться.

Способ 2. Выгрузка в ТаблицуЗначений и сворачивание

Когда требуется быстро определить сам факт наличия дублей и оставить только уникальные комбинации, удобно использовать методы объекта ТаблицаЗначений. Мы выгружаем табличную часть, добавляем счетчик и выполняем группировку.

Разберем по шагам последовательность действий:

  1. Выгружаем строки ТЧ во временную таблицу значений методом ВыгрузитьТабличнуюЧасть().
  2. Добавляем числовую колонку-счетчик с помощью метода НоваяКолонка() и заполняем её единицами.
  3. Вызываем метод Свернуть(), передав в качестве первого параметра группировочные колонки, а в качестве второго — колонку-счетчик.
  4. Все строки, где значение счетчика больше единицы, содержат дублировавшиеся данные.

Рассмотрим пример кода:


ТЗ = СоздатьОбъект("ТаблицаЗначений");
ВыгрузитьТабличнуюЧасть(ТЗ);

ТЗ.НоваяКолонка("СчетчикДублей", "Число", 5, 0);
ТЗ.ВыбратьСтроки();
Пока ТЗ.ПолучитьСтроку() = 1 Цикл
    ТЗ.СчетчикДублей = 1;
КонецЦикла;

// Сворачиваем по проверяемому реквизиту с суммированием счетчика
ТЗ.Свернуть("ИскомыйРеквизит", "СчетчикДублей");

// ТЗ теперь содержит только уникальные значения
// Строки со значением СчетчикДублей > 1 исходно имели дубликаты
ТЗ.ВыбратьСтроки();
Пока ТЗ.ПолучитьСтроку() = 1 Цикл
    Если ТЗ.СчетчикДублей > 1 Тогда
        Сообщить("Значение " + СокрЛП(ТЗ.ИскомыйРеквизит) + " дублируется " + ТЗ.СчетчикДублей + " раз(а).");
    КонецЕсли;
КонецЦикла;

Способ 3. Сортировка и сравнение соседних строк

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

Проанализируем пример кода:


ТЗ = СоздатьОбъект("ТаблицаЗначений");
ВыгрузитьТабличнуюЧасть(ТЗ);

// Сортируем таблицу по ключевому полю
ТЗ.Сортировать("ИскомыйРеквизит+");

ПредыдущееЗначение = "";
НомерСтр = ТЗ.КоличествоСтрок();

Пока НомерСтр > 0 Цикл
    ТЗ.ПолучитьСтрокуПоНомеру(НомерСтр);
    Если НомерСтр < ТЗ.КоличествоСтрок() Тогда
        Если ТЗ.ИскомыйРеквизит = ПредыдущееЗначение Тогда
            ТЗ.УдалитьСтроку(НомерСтр);
        КонецЕсли;
    КонецЕсли;
    ПредыдущееЗначение = ТЗ.ИскомыйРеквизит;
    НомерСтр = НомерСтр - 1;
КонецЦикла;

Способ 4. Высокопроизводительный поиск через Scripting.Dictionary

Для мгновенной обработки десятков тысяч строк в 1С 7.7 платформенных возможностей СписокЗначений может быть недостаточно из-за сложности поиска. В таких случаях рекомендуется использовать внешний COM-объект Scripting.Dictionary (хеш-таблица Windows), где метод Exists() работает практически мгновенно.

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


ХешТаблица = СоздатьОбъект("Scripting.Dictionary");
КолСтрок = КоличествоСтрок();

Пока КолСтрок > 0 Цикл
    ПолучитьСтрокуПоНомеру(КолСтрок);
    Ключ = СокрЛП(ВРег(Строка(Реквизит)));
    
    Если ХешТаблица.Exists(Ключ) = 0 Тогда
        ХешТаблица.Add(Ключ, 1);
    Иначе
        УдалитьСтроку();
    КонецЕсли;
    
    КолСтрок = КолСтрок - 1;
КонецЦикла;

Особенности нормализации данных при поиске дублей

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

  1. Регистр символов и пробелы: строки обязательно следует приводить к единому регистру функцией ВРег() и отсекать концевые пробелы функцией СокрЛП().
  2. Параметры метода НайтиПоНаименованию(): при проверке элементов справочников помните, что метод НайтиПоНаименованию(Имя, 0, 0) вторым параметром принимает режим соответствия: 0 — точное совпадение, 1 — поиск по начальной части. По умолчанию в 1С 7.7 включен поиск по началу строки, что может привести к ложному определению дублей.
  3. Очистка спецсимволов: при сравнении телефонов или паспортных номеров предварительно удаляйте маски, дефисы и скобки, оставляя только числовую последовательность.
← На главную