К статье
Практический материал

Разработка и Конфигурация · 11 мин

Как найти элемент массива в 1С: все рабочие способы с примерами

Способы найти элемент массива в 1С: метод Найти, перебор в цикле, поиск по условию и в массиве структур. Примеры кода, проверка результата и типичные ошибки.

Массив в 1С — одна из самых используемых коллекций: в него складывают ссылки на документы, строки табличных частей, результаты запросов и произвольные значения для дальнейшей обработки. Задача «найти элемент массива» возникает постоянно: проверить, есть ли значение в списке, получить индекс нужного элемента или отобрать строки по сложному условию.

Встроенный язык 1С предлагает несколько инструментов для этого: метод Найти(), классический перебор в цикле, а для массивов структур — вспомогательные приёмы через таблицу значений или функцию сравнения. У каждого подхода есть свои ограничения: Найти() работает только с точным совпадением значения, цикл универсален, но требует аккуратности, а выбор неправильного метода приводит к лишним затратам времени на больших объёмах данных.

Ниже разобраны все рабочие способы поиска с готовыми примерами кода, проверкой результата и разбором типичных ошибок. Примеры приведены на встроенном языке 1С и работают как в тонком клиенте, так и на сервере.

Как устроен поиск в массиве 1С

Массив в 1С — это упорядоченная коллекция значений с доступом по индексу, начиная с нуля. Элементы могут быть любого типа: числа, строки, ссылки, структуры и даже другие массивы. Платформа не хранит никакого внутреннего индекса для быстрого поиска, поэтому любой поиск — это последовательное сравнение значений, просто метод Найти() делает это за вас.

Из этого следуют два практических вывода. Во-первых, поиск по массиву из нескольких тысяч элементов внутри другого цикла — типичный источник «тормозов»: сложность растёт квадратично. Во-вторых, сравнение идёт по значению, и для ссылочных типов два разных объекта с одинаковым содержимым не считаются равными — равны только ссылки на один и тот же объект базы данных.

Метод Найти(): поиск точного совпадения

Основной инструмент — метод Найти(Значение). Он возвращает индекс первого найденного элемента или Неопределено, если значение в массиве отсутствует. Именно возврат Неопределено, а не минус единицы, чаще всего становится источником ошибок у тех, кто пришёл из других языков.

МассивКонтрагентов = Новый Массив;

МассивКонтрагентов.Добавить("ООО Ромашка");

МассивКонтрагентов.Добавить("ИП Сидоров");

МассивКонтрагентов.Добавить("АО Вектор");

Индекс = МассивКонтрагентов.Найти("ИП Сидоров");

Если Индекс <> Неопределено Тогда

Сообщить("Найдено, индекс: " + Индекс);

Иначе

Сообщить("Значение не найдено");

КонецЕсли;

Метод сравнивает значения строго. Для строк сравнение идёт с учётом регистра: «Ромашка» и «ромашка» — разные значения. Для чисел тип значения тоже имеет значение в ряде ситуаций, поэтому перед поиском строки в массиве чисел стоит явно привести типы через Число() или Строка().

bsl
Индекс = Массив.Найти(ИскомоеЗначение);
Если Индекс = Неопределено Тогда
    // значение отсутствует в массиве
КонецЕсли;

Поиск в цикле: когда Найти() недостаточно

Метод Найти() умеет только точное равенство. Если нужно найти элемент по части строки, по диапазону чисел, по признаку пометки на удаление у ссылки или по любому другому условию — используйте перебор с ручной проверкой.

Цикл Для Каждого

Конструкция Для Каждого ... Цикл подходит, когда индекс не нужен, а важен сам элемент. Прервать перебор после первого совпадения можно оператором Прервать — это экономит время на больших массивах.

НайденныйЭлемент = Неопределено;

Для Каждого Элемент Из МассивКонтрагентов Цикл

Если СтрНайти(Элемент, "ИП") > 0 Тогда

НайденныйЭлемент = Элемент;

Прервать;

КонецЕсли;

КонецЦикла;

Цикл со счётчиком, когда нужен индекс

Если по условию нужно получить именно позицию элемента (например, чтобы потом удалить его методом Удалить(Индекс)), используйте цикл со счётчиком через ВГраница():

ИндексНайденного = Неопределено;

Для Сч = 0 По МассивКонтрагентов.ВГраница() Цикл

Если СтрНайти(МассивКонтрагентов[Сч], "ИП") > 0 Тогда

ИндексНайденного = Сч;

Прервать;

КонецЕсли;

КонецЦикла;

Поиск в массиве структур

На практике массивы часто содержат структуры: например, строки данных с полями «Номенклатура», «Количество», «Цена». Метод Найти() здесь бесполезен — две структуры с одинаковым содержимым не равны друг другу, а сравнивать нужно по конкретному полю.

Решение — перебор с обращением к свойству структуры:

ИскомаяНоменклатура = Справочники.Номенклатура.НайтиПоКоду("000001");

НайденнаяСтрока = Неопределено;

Для Каждого СтрокаДанных Из МассивСтруктур Цикл

Если СтрокаДанных.Номенклатура = ИскомаяНоменклатура Тогда

НайденнаяСтрока = СтрокаДанных;

Прервать;

КонецЕсли;

КонецЦикла;

Если массив структур большой и поиск выполняется многократно, выгоднее один раз выгрузить данные в таблицу значений и пользоваться методом НайтиСтроки(Отбор) — он возвращает массив всех подходящих строк и работает заметно быстрее ручного перебора при повторных поисках. Таблица значений создаётся программно, колонки добавляются методом Колонки.Добавить().

Сравнение способов поиска

Метод Найти()

Точное совпадение простых значений и ссылок. Самый короткий код, но не работает с условиями и структурами.

Цикл Для Каждого

Любое условие, поиск по полям структур. Универсально, но требует ручной проверки и Прервать для оптимизации.

Таблица значений + НайтиСтроки

Многократный поиск по нескольким полям в больших объёмах. Требует затрат на создание и заполнение таблицы.

Соответствие

Когда поиск идёт по уникальному ключу много раз: ключ — искомое значение, значение — нужные данные. Самый быстрый повторный поиск.

Как проверить результат поиска

Главное правило: всегда проверяйте результат на Неопределено перед использованием. Обращение к элементу по индексу Неопределено вызовет ошибку исполнения и прервёт обработку, а в серверном коде — приведёт к откату транзакции.

Индекс = МассивДокументов.Найти(ДокументСсылка);

Если Индекс = Неопределено Тогда

// Документа в массиве нет — добавляем

МассивДокументов.Добавить(ДокументСсылка);

КонецЕсли;

Отдельно проверяйте граничные случаи: пустой массив (Найти() корректно вернёт Неопределено, но цикл со счётчиком просто не выполнится), поиск значения Неопределено внутри массива (тоже работает через Найти(Неопределено)) и поиск ссылки, которая могла быть удалена из базы — сравнение пройдёт, но обращение к реквизитам «битой» ссылки выдаст ошибку.

Контрольные точки

Как проверить результат

Возвращаемое значение Найти()
Норма

Число от 0 до ВГраница()

Тревожный признак

Неопределено — элемент не найден, индекс использовать нельзя

Тип искомого значения
Норма

Тип совпадает с типом элементов массива

Тревожный признак

Строка ищется в массиве чисел — поиск всегда безуспешен

Регистр строк
Норма

Регистр искомой строки совпадает с элементом

Тревожный признак

«ромашка» не находит «Ромашка» — применяйте ВРег() к обеим строкам

Производительность: когда массив — не лучший инструмент

Если в обработке выполняется поиск вида «для каждой строки документа проверить, есть ли товар в массиве», на больших объёмах это становится узким местом. Массив не индексируется, и каждый вызов Найти() — это перебор до совпадения.

Для таких сценариев замените массив на соответствие: ключ — искомое значение, значение — Истина или нужные данные. Проверка Соответствие.Получить(Ключ) <> Неопределено выполняется практически мгновенно независимо от размера коллекции. Альтернатива — перенести логику в запрос: условие В (&МассивЗначений) позволяет передать массив параметром и выполнить отбор на стороне СУБД, что почти всегда быстрее программного перебора.

Маршрут решения

Как выбрать способ

Нужно проверить наличие точного значения один-два разаИспользуйте Массив.Найти(Значение) с проверкой на Неопределено
Поиск по условию или по полю структурыПеребирайте массив циклом Для Каждого с Прервать после находки
Поиск выполняется многократно по ключуПереведите данные в Соответствие и ищите через Получить(Ключ)
Нужно отобрать данные из базы по списку значенийПередайте массив параметром в запрос с условием В (&amp;Параметр)

Типичные ошибки при поиске в массиве

Большинство проблем с поиском в массиве сводится к нескольким повторяющимся сценариям. Первая — сравнение результата Найти() с нулём или минус единицей вместо Неопределено: условие Если Индекс >= 0 при ненайденном значении даст ложное срабатывание, потому что Неопределено в таком сравнении ведёт себя неочевидно и код «находит» несуществующий элемент.

Вторая группа ошибок — несовпадение типов и регистра. Поиск строки «123» в массиве чисел ничего не найдёт, как и поиск «контрагент» вместо «Контрагент». Перед поиском приводите значения к одному типу и, при необходимости, к одному регистру через ВРег() или НРег().

Третья частая проблема — удаление элементов массива внутри цикла перебора по индексу снизу вверх нарушено: после Удалить(Индекс) все последующие элементы сдвигаются, и цикл «вверх» пропускает элементы. Если нужно удалять по условию, идите по массиву от конца к началу или собирайте индексы для удаления в отдельный список.

Типичные ошибки
01
Сравнение результата Найти() с 0 или -1 вместо Неопределено — ложные срабатывания и обращение по неверному индексу
02
Поиск строки в массиве чисел без приведения типов — поиск всегда возвращает Неопределено
03
Игнорирование регистра при сравнении строк — «москва» не находит «Москва»
04
Удаление элементов в прямом цикле по индексу — пропуск элементов после сдвига массива
05
Использование Найти() для массива структур — структуры не сравниваются по содержимому, поиск не сработает

Частые вопросы

Что возвращает метод Найти(), если элемент не найден?

Метод возвращает значение Неопределено, а не -1 и не 0. Поэтому результат всегда проверяйте конструкцией «Если Индекс = Неопределено Тогда». Сравнение с числом приведёт к ошибкам логики.

Как найти элемент массива без учёта регистра?

Метод Найти() всегда учитывает регистр. Для поиска без учёта регистра переберите массив в цикле и сравнивайте ВРег(Элемент) = ВРег(ИскомаяСтрока), прерывая цикл после первого совпадения.

Можно ли найти в массиве сразу все вхождения значения?

Метод Найти() возвращает только первое вхождение. Чтобы получить все, переберите массив циклом со счётчиком и сохраняйте индексы совпадений в отдельный массив, не прерывая обход.

Как найти строку в массиве структур по двум полям одновременно?

В цикле Для Каждого проверяйте оба условия через И: «Если Строка.Номенклатура = Искомая И Строка.Склад = ИскомыйСклад Тогда». При многократных поисках выгрузите данные в таблицу значений и используйте НайтиСтроки с структурой отбора.

Почему Найти() не находит ссылку, которая точно есть в массиве?

Чаще всего сравниваются ссылки разных видов или ссылка с её строковым представлением. Убедитесь, что ищете именно ссылку того же типа, а не код, наименование или уникальный идентификатор в виде строки.

Что быстрее: поиск в массиве или в соответствии?

Для однократного поиска разницы почти нет. При многократных проверках соответствие значительно быстрее: поиск по ключу в нём не зависит от размера коллекции, тогда как массив перебирается каждый раз заново.

Итог

Что важно запомнить

Для точного совпадения используйте Массив.Найти(Значение) и всегда проверяйте результат на Неопределено. Для условий и массивов структур — цикл Для Каждого с Прервать. При многократных поисках заменяйте массив на соответствие или таблицу значений, а отбор по списку значений из базы делайте запросом с параметром В (&amp;Массив).