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