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

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

Как найти элемент в массиве структур в 1С

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

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

Главная сложность в том, что у массива нет встроенного поиска по значению поля структуры. Метод Найти() массива сравнивает элементы целиком, а структуры в 1С сравниваются по ссылке, а не по содержимому. Поэтому прямой вызов Массив.Найти(СтруктураПоиска) почти никогда не даст результата, даже если «такая же» структура в массиве есть.

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

Почему Массив.Найти() не работает со структурами

Метод Найти() массива ищет элемент, равный переданному значению. Для примитивных типов (число, строка, дата) и ссылок это работает корректно. Но структура — объект, и две структуры с одинаковым составом и значениями считаются разными объектами: сравнение идёт по идентичности, а не по содержимому.

На практике это выглядит так: вы создаёте структуру-шаблон Новый Структура("Контрагент, Сумма", ИскомыйКонтрагент, 1000) и передаёте её в Массив.Найти(). Результат — Неопределено, даже если в массиве лежит структура с точно такими же значениями. Это не ошибка платформы, а ожидаемое поведение.

Базовый способ: перебор в цикле с проверкой ключа

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

Функция НайтиСтрокуПоНоменклатуре(МассивСтрок, ИскомаяНоменклатура)

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

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

Возврат Элемент;

КонецЕсли;

КонецЦикла;

Возврат Неопределено; // не найдено

КонецФункции

Обратите внимание на контракт функции: при отсутствии результата возвращается Неопределено. Вызывающий код обязан проверить это значение до обращения к полям найденной структуры, иначе получите ошибку «Поле объекта не обнаружено».

Порядок действий при поиске в цикле
  1. 1
    Определите ключ поиска — поле структуры, по которому ищете
  2. 2
    Напишите цикл Для Каждого по массиву
  3. 3
    Внутри цикла сравните поле элемента с искомым значением
  4. 4
    При совпадении верните элемент и прервите цикл
  5. 5
    После цикла верните Неопределено как признак «не найдено»
  6. 6
    В вызывающем коде проверьте результат на Неопределено

Поиск по нескольким условиям и сбор всех совпадений

Если элемент идентифицируется комбинацией полей — например, контрагент и договор, — условия объединяются оператором И. Важно, чтобы все поля гарантированно присутствовали в структурах, иначе обращение к отсутствующему ключу вызовет исключение.

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

Если Элемент.Контрагент = ИскомыйКонтрагент

И Элемент.Договор = ИскомыйДоговор Тогда

Возврат Элемент;

КонецЕсли;

КонецЦикла;

Когда нужны все подходящие элементы, а не первый, цикл не прерывается, а совпадения складываются в новый массив:

Результат = Новый Массив;

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

Если Элемент.Склад = ИскомыйСклад Тогда

Результат.Добавить(Элемент);

КонецЕсли;

КонецЦикла;

Признак корректной работы такого варианта — пустой массив при отсутствии совпадений. Проверяйте Результат.Количество() = 0, а не сравнение с Неопределено: функция возвращает массив всегда.

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

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

Таблица = Новый ТаблицаЗначений;

Таблица.Колонки.Добавить("Номенклатура");

Таблица.Колонки.Добавить("Количество");

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

СтрокаТЗ = Таблица.Добавить();

СтрокаТЗ.Номенклатура = Элемент.Номенклатура;

СтрокаТЗ.Количество = Элемент.Количество;

КонецЦикла;

НайденнаяСтрока = Таблица.Найти(ИскомаяНоменклатура, "Номенклатура");

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

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

Перебор массива в цикле

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

Таблица значений + Найти()

Подходит для многократного поиска и отборов по нескольким полям. Требует однократного переноса данных и описания колонок.

Соответствие с ключом-значением

Мгновенный поиск по одному уникальному ключу. Не работает для составных условий и неуникальных значений.

Альтернатива: соответствие вместо массива

Если вы сами формируете структуру данных и знаете, что поиск будет идти по одному уникальному полю (код, артикул, ссылка), лучше сразу использовать соответствие, где ключ — это поле, а значение — структура или сам объект.

Индекс = Новый Соответствие;

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

Индекс.Вставить(Элемент.Артикул, Элемент);

КонецЦикла;

НайденныйЭлемент = Индекс.Получить(ИскомыйАртикул);

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

Безопасное обращение к полям структуры

Частая причина падения поиска — обращение к полю, которого нет в части структур массива. Если состав структур не гарантирован, проверяйте наличие ключа через метод Свойство():

ЗначениеПоля = Неопределено;

Если Элемент.Свойство("Склад", ЗначениеПоля)

И ЗначениеПоля = ИскомыйСклад Тогда

Возврат Элемент;

КонецЕсли;

Ещё одна тонкость — сравнение значений разных типов. Строка «001» и число 1 не равны, ссылка и её строковое представление — тоже. Перед сравнением убедитесь, что типы совпадают, или приведите их явно. Для строк без учёта регистра используйте ВРег() к обеим сторонам сравнения.

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

Как проверить, что поиск работает правильно

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

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

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

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

Элемент существует в массиве
Норма

Функция возвращает структуру с ожидаемыми значениями полей

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

Возвращается Неопределено или другой элемент

Элемента нет в массиве
Норма

Возвращается Неопределено, исключений нет

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

Ошибка обращения к полю или возврат произвольного элемента

Повторный поиск по тому же массиву
Норма

Результат стабилен при неизменных данных

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

Результат меняется — вероятно, данные модифицируются в процессе

FAQ

Можно ли найти элемент массива структур без цикла?

Штатного метода поиска по значению поля структуры у массива нет. Без явного цикла задачу решают таблица значений с методом Найти() или соответствие с ключом по искомому полю — но в обоих случаях данные всё равно один раз перебираются при построении.

Почему поиск не находит элемент, хотя он точно есть в массиве?

Чаще всего причины три: сравниваются значения разных типов, в строках есть лишние пробелы или разный регистр, либо используется Массив.Найти() со структурой, который сравнивает объекты по ссылке. Выведите значения и типы обеих сторон сравнения — расхождение станет видно сразу.

Как найти элемент по части строки, а не по точному совпадению?

Используйте функцию СтрНайти() внутри условия цикла: Если СтрНайти(Элемент.Наименование, ИскомыйФрагмент) > 0 Тогда. Учтите, что такой поиск регистрозависим; для поиска без учёта регистра приведите обе строки через ВРег().

Что быстрее: перебор массива или таблица значений?

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

Как вернуть индекс найденного элемента, а не сам элемент?

Используйте цикл со счётчиком вместо Для Каждого: Для Индекс = 0 По Массив.ВГраница() Цикл, и при совпадении возвращайте переменную Индекс. Признак «не найдено» в этом случае — значение -1.

Опасно ли изменять найденную структуру прямо в массиве?

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

Итог

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

Массив.Найти() не ищет структуры по содержимому — используйте перебор в цикле с проверкой ключа и выходом после первого совпадения. Для многократного поиска переносите данные в таблицу значений с индексом или стройте соответствие по уникальному полю. Всегда проверяйте результат на Неопределено и следите за совпадением типов сравниваемых значений.