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