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