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