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