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