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

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

Как найти значение в массиве структур в 1С

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

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

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

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

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

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

Способ 1: перебор массива с проверкой полей

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

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

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

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

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

КонецЕсли;

КонецЦикла;

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

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

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

Поиск всех подходящих элементов

Если условию может соответствовать несколько структур, не прерывайте цикл, а собирайте результаты в новый массив:

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

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

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

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

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

КонецЕсли;

КонецЦикла;

Возврат Результат;

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

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

Способ 2: поиск с несколькими условиями

Когда критериев несколько, условия объединяются логическими операторами внутри цикла. Здесь Поэтому обращение к полю, которого может не быть в структуре, приведёт к ошибке независимо от результата предыдущей проверки.

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

Если Элемент.Свойство("Количество")

И Элемент.Свойство("Цена")

И Элемент.Количество > 0

И Элемент.Цена <= МаксимальнаяЦена Тогда

// элемент подходит

КонецЕсли;

КонецЦикла;

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

Типичные ошибки
01
Сравнение строк без учёта регистра: «Товар» и «товар» не равны — приводите обе строки к одному регистру через ВРег() или НРег()
02
Обращение к полю структуры без проверки его наличия — ошибка «Поле объекта не обнаружено» на разнородных массивах
03
Отсутствие проверки результата поиска на Неопределено перед использованием найденной структуры
04
Сравнение числа и строкового представления числа: «10» <> 10 — приводите типы перед сравнением

Способ 3: таблица значений и НайтиСтроки

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

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

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

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

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

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

ЗаполнитьЗначенияСвойств(Строка, Элемент);

КонецЦикла;

Отбор = Новый Структура("Артикул", ИскомыйАртикул);

НайденныеСтроки = Таблица.НайтиСтроки(Отбор);

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

Сравнение вариантов

Перебор циклом

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

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

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

Соответствие (ключ — значение поля)

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

Способ 4: соответствие для многократного поиска

Когда поиск по одному и тому же массиву выполняется десятки или сотни раз (например, сопоставление данных из внешнего файла с данными базы), оптимальное решение — построить соответствие, где ключом служит искомое поле, а значением — сама структура или её индекс в массиве.

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

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

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

КонецЦикла;

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

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

// элемент найден

КонецЕсли;

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

Порядок действий
  1. 1
    Определите, сколько раз будет выполняться поиск: один раз или многократно
  2. 2
    Для разового поиска напишите цикл Для Каждого с проверкой поля и возвратом Неопределено при неудаче
  3. 3
    Для многократного поиска постройте соответствие по ключевому полю или преобразуйте массив в таблицу значений
  4. 4
    Проверьте наличие ключей в структурах через Свойство() при разнородных данных
  5. 5
    Проверьте результат поиска на Неопределено до обращения к полям найденного элемента

Проверка результата и отладка

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

При отладке несоответствий полезно вывести фактические значения полей через Сообщить() или посмотреть их в табло конфигуратора. Частая ситуация: поиск «не находит» элемент, который визуально присутствует, — почти всегда причина в разном регистре строк, лишних пробелах (используйте СокрЛП()) или различии типов значений.

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

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

Функция поиска на тестовых данных
Норма

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

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

Возвращает Неопределено при заведомо существующем значении — проверяйте регистр, пробелы и типы

Массив с разнородными структурами
Норма

Поиск не падает на элементах без искомого ключа

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

Ошибка «Поле объекта не обнаружено» — добавьте проверку через Свойство()

Поиск по нескольким условиям
Норма

Возвращаются только элементы, удовлетворяющие всем критериям

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

Лишние элементы в результате — проверьте логику И/ИЛИ и скобки

Производительность и ограничения

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

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

Итог

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

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

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

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

Прямого метода нет — перебирайте массив и используйте функцию СтрНайти(Элемент.Наименование, Подстрока) > 0. Учтите, что поиск по подстроке чувствителен к регистру; при необходимости приводите обе строки к одному регистру через НРег().

Можно ли сравнить две структуры на равенство содержимого?

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

Что вернёт Соответствие.Получить(), если ключа нет?

Метод вернёт Неопределено, ошибки не будет. Поэтому результат всегда нужно проверять перед обращением к полям найденной структуры.

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

Используйте цикл со счётчиком (Для Индекс = 0 По Массив.ВГраница() Цикл) и при совпадении условия возвращайте значение счётчика. Индекс нужен, например, чтобы удалить элемент методом Массив.Удалить(Индекс).

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

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