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