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