СписокЗначений во встроенном языке 1С 8.3: от конструктора до формы

· 9 мин

Содержание

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

Выбор коллекции простой. Нужен набор значений для выбора, отметки галочками или параметра запроса — берите список значений. Нужны только данные без подписей — хватит массива. Нужно быстро проверять «есть ли ключ» — Соответствие. Нужно несколько колонок — таблица значений. Ниже работа со списком значений разобрана по шагам: методы, сортировка, конвертация, формы и производительность.

Создание списка значений и первые строки кода

Объект создаётся одной строкой. Работает и на сервере, и на клиенте, в том числе в веб-клиенте.

Список = Новый СписокЗначений;
Список.Добавить(1, "Январь");
Список.Добавить(2, "Февраль");
Список.Добавить(3, "Март", Истина); // третий параметр — пометка

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

Элемент = Список.Добавить(Справочники.Валюты.НайтиПоКоду("840"));
Элемент.Представление = "Доллар США";
Элемент.Пометка = Истина;

Ограничение по типу значений

По умолчанию в список можно положить что угодно: число, строку, ссылку, даже другой список. Если нужна строгость, задайте свойство ТипЗначения:

Список.ТипЗначения = Новый ОписаниеТипов("СправочникСсылка.Номенклатура");

Это особенно полезно для списка, который пользователь редактирует на форме: поле значения сразу будет предлагать выбор из нужного справочника.

Что хранит каждый элемент

СвойствоТипЗачем
Значениепроизвольныйсами данные: ссылка, число, строка
Представлениестрокаподпись для пользователя; если пустая, выводится значение
Пометкабулевогалочка — для множественного выбора
Картинкакартинказначок рядом со строкой в интерфейсе

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

Методы списка значений: заполнение, поиск, удаление

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

МетодЧто делает
Добавить(Значение, …)добавляет элемент в конец
Вставить(Индекс, Значение, …)вставляет элемент на позицию
ЗагрузитьЗначения(Массив)заменяет содержимое значениями из массива
ВыгрузитьЗначения()возвращает массив значений
НайтиПоЗначению(Значение)первый элемент с таким значением или Неопределено
НайтиПоИдентификатору(Ид)элемент по идентификатору (нужно на формах)
Получить(Индекс)элемент по номеру
Индекс(Элемент)номер элемента
Количество()число элементов
Сдвинуть(Элемент, Смещение)перемещает элемент вверх или вниз
Удалить(Элемент или Индекс)удаляет один элемент
Очистить()удаляет все элементы
Скопировать()создаёт копию списка
ЗаполнитьПометки(Пометка)ставит или снимает все галочки разом

Заполнение из массива и обратно

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

Массив = Новый Массив;
Массив.Добавить("Москва");
Массив.Добавить("Казань");

Список.ЗагрузитьЗначения(Массив);   // в списке два элемента
МассивОбратно = Список.ВыгрузитьЗначения();

Обход элементов

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

Для Каждого Элемент Из Список Цикл
    Сообщить(Элемент.Представление + ": " + Строка(Элемент.Значение));
КонецЦикла;

Обращение по индексу тоже работает: Список[0].Значение — значение первого элемента.

Поиск элемента

Найденный = Список.НайтиПоЗначению(2);
Если Найденный <> Неопределено Тогда
    НомерСтроки = Список.Индекс(Найденный); // 1
КонецЕсли;

Метод возвращает первый подходящий элемент. Если значение встречается дважды, второй элемент он не покажет: для этого нужен свой цикл.

Ссылки сравниваются по ссылке, а не по наименованию. Строки сравниваются с учётом регистра: "Москва" и "москва" — разные значения. Если ищете по тексту, введённому пользователем, приводите обе стороны к одному виду через НРег().

Сортировка и фильтрация данных в списке значений

Два метода сортировки

У списка два встроенных метода:

  • 🔢 СортироватьПоЗначению(НаправлениеСортировки.Возр) — по самим значениям;
  • 🔤 СортироватьПоПредставлению(НаправлениеСортировки.Убыв) — по подписям.

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

Список.СортироватьПоПредставлению(); // Март, Февраль, Январь

Сортировка по значению для ссылок не обязана совпадать с алфавитным порядком наименований. Хотите алфавит — заполните представления наименованиями и сортируйте по представлению.

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

Фильтрация: своего метода нет

Отбора у списка значений нет, фильтр пишут циклом. Два рабочих варианта.

Вариант 1. Собрать новый список. Исходный остаётся целым — так проще отлаживать.

Отмеченные = Новый СписокЗначений;
Для Каждого Элемент Из Список Цикл
    Если Элемент.Пометка Тогда
        Отмеченные.Добавить(Элемент.Значение, Элемент.Представление);
    КонецЕсли;
КонецЦикла;

Вариант 2. Удалить лишнее из исходного. Здесь цикл идёт только с конца. При прямом проходе после удаления элементы сдвигаются, и соседний элемент пропускается.

Всего = Список.Количество();
Для Сч = 1 По Всего Цикл
    Элемент = Список[Всего - Сч];
    Если Не Элемент.Пометка Тогда
        Список.Удалить(Элемент);
    КонецЕсли;
КонецЦикла;

Граница Всего вычисляется один раз до цикла. Индекс Всего - Сч идёт от последнего элемента к нулевому, и удаление не задевает те, что ещё не проверены.

Список значений и таблица значений: конвертация в обе стороны

Прямого метода «превратить список в таблицу» нет. Обе задачи решаются в несколько строк.

Из таблицы значений в список

Если нужна одна колонка, хватит одной строки — через массив:

Список.ЗагрузитьЗначения(ТЗ.ВыгрузитьКолонку("Номенклатура"));

Если нужны ещё и представления, обходите строки:

Для Каждого Строка Из ТЗ Цикл
    Список.Добавить(Строка.Номенклатура, Строка.Артикул + " " + Строка.Наименование);
КонецЦикла;

Дубли из колонки сначала убирают в самой таблице: ТЗ.Свернуть("Номенклатура"), а уже потом выгружают колонку.

Из списка в таблицу значений

ТЗ = Новый ТаблицаЗначений;
ТЗ.Колонки.Добавить("Значение");
ТЗ.Колонки.Добавить("Представление", Новый ОписаниеТипов("Строка"));
ТЗ.Колонки.Добавить("Пометка", Новый ОписаниеТипов("Булево"));

Для Каждого Элемент Из Список Цикл
    НоваяСтрока = ТЗ.Добавить();
    ЗаполнитьЗначенияСвойств(НоваяСтрока, Элемент);
КонецЦикла;

ЗаполнитьЗначенияСвойств() переносит свойства с совпадающими именами, поэтому колонки названы так же, как свойства элемента.

Когда что выбирать

ЗадачаКоллекция
Выбор из вариантов, галочки, параметр «В (&Список)»список значений
Несколько колонок, группировка, итогитаблица значений
Быстрая проверка «есть ли ключ»соответствие
Простой набор данных без подписеймассив

Список значений как параметр запроса

Это одно из самых частых применений. Список подставляется в условие В:

Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ
|    Номенклатура.Ссылка,
|    Номенклатура.Наименование
|ИЗ
|    Справочник.Номенклатура КАК Номенклатура
|ГДЕ
|    Номенклатура.Ссылка В (&Отобранные)";
Запрос.УстановитьПараметр("Отобранные", Отмеченные);

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

Список значений на управляемой форме

Реквизит формы типа «СписокЗначений»

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

Реквизит такого типа доступен и на клиенте, и на сервере. Отдельно передавать его в серверный вызов не нужно: он уходит вместе с данными формы.

Строки таблицы на форме связаны с элементами через идентификатор. В обработчике выбора строки получить элемент так:

&НаКлиенте
Процедура СписокВыбор(Элемент, ВыбраннаяСтрока, Поле, СтандартнаяОбработка)
    ЭлементСписка = Список.НайтиПоИдентификатору(ВыбраннаяСтрока);
    Сообщить(ЭлементСписка.Значение);
КонецПроцедуры

Список выбора у поля ввода

У поля ввода есть свойство СписокВыбора — это тоже список значений. Его можно заполнить в конфигураторе, в палитре свойств, или программно при открытии формы:

&НаСервере
Процедура ПриСозданииНаСервере(Отказ, СтандартнаяОбработка)
    Элементы.Период.СписокВыбора.Добавить("Месяц", "За месяц");
    Элементы.Период.СписокВыбора.Добавить("Квартал", "За квартал");
КонецПроцедуры

Чтобы пользователь видел выпадающий список, включите у поля кнопку выпадающего списка. Чтобы нельзя было ввести своё значение, включите режим «Только выбор из списка» — свойство РежимВыбораИзСписка.

Выбор и отметка элементов в диалоге

Список умеет сам показать пользователю окно выбора. В 8.3 используйте немодальные методы с оповещением:

  • ✅ ПоказатьВыборЭлемента(Оповещение, Заголовок) — выбор одного элемента;
  • ☑️ ПоказатьОтметкуЭлементов(Оповещение, Заголовок) — выбор нескольких галочками.
&НаКлиенте
Процедура ВыбратьМесяц(Команда)
    Месяцы = Новый СписокЗначений;
    Месяцы.Добавить(1, "Январь");
    Месяцы.Добавить(2, "Февраль");
    Оповещение = Новый ОписаниеОповещения("ПослеВыбораМесяца", ЭтотОбъект);
    Месяцы.ПоказатьВыборЭлемента(Оповещение, "Выберите месяц");
КонецПроцедуры

&НаКлиенте
Процедура ПослеВыбораМесяца(ВыбранныйЭлемент, ДополнительныеПараметры) Экспорт
    Если ВыбранныйЭлемент = Неопределено Тогда
        Возврат; // пользователь закрыл окно
    КонецЕсли;
    Сообщить(ВыбранныйЭлемент.Представление);
КонецПроцедуры

Процедура-обработчик обязательно экспортная, иначе платформа её не вызовет. Модальные ВыбратьЭлемент() и ОтметитьЭлементы() при запрете модальности в свойствах конфигурации выдадут ошибку, а в веб-клиенте их лучше не применять вовсе.

Производительность и типичные ошибки при работе со списком

Где список значений тормозит

  • 🐢 Поиск в цикле. НайтиПоЗначению() перебирает элементы по порядку. Проверка 10 000 значений по списку из 10 000 элементов — это до 100 миллионов сравнений. Для таких проверок заведите Соответствие, где ключ — значение, и ищите в нём.
  • 🐢 Вставка в начало. Вставить(0, …) сдвигает все элементы. Если порядок важен, добавляйте в конец, а потом сортируйте один раз.
  • 🐢 Огромный список в условии В. Для десятков тысяч значений надёжнее передать таблицу значений в запрос, положить её во временную таблицу и соединиться с ней.
  • 🐢 Лишние серверные вызовы. Заполнение списка на клиенте, где каждое значение берётся отдельным вызовом сервера, медленнее, чем одна серверная процедура, которая заполнит всё и вернёт готовый список.

Пример с соответствием для быстрой проверки:

Индекс = Новый Соответствие;
Для Каждого Элемент Из Список Цикл
    Индекс.Вставить(Элемент.Значение, Истина);
КонецЦикла;

Если Индекс[ИскомаяСсылка] = Истина Тогда
    // значение есть в списке
КонецЕсли;

Ошибки, которые встречаются чаще всего

ОшибкаЧто происходитКак правильно
Удаление в прямом циклепропускается каждый второй элементобратный цикл с границей до начала цикла
Элемент = Ссылкаусловие всегда ложносравнивать Элемент.Значение
Нет проверки на Неопределеноошибка «Значение не является значением объектного типа»проверять результат НайтиПоЗначению()
ЗагрузитьЗначения() в непустой списокстарые элементы пропадаютсначала выгрузить, объединить массивы, потом загрузить
Присвоение Список2 = Список1оба имени указывают на один объектдля отдельной копии вызвать Скопировать()
Список[Список.Количество()]выход за границупоследний элемент — Количество() - 1

Отдельно о присвоении. Изменение Список2 после Список2 = Список1 меняет и исходный список. Это частая причина «загадочных» багов, когда функция портит переданный ей параметр. Если процедура не должна менять входной список, работайте с копией.

Проверьте себя
Что вернёт НайтиПоЗначению(), если значения нет в списке?
Каким способом безопасно удалить элементы из списка в цикле?
Что попадёт в запрос, если передать список значений параметром условия В?

Частые вопросы о списке значений

Можно ли хранить в списке значений разные типы?
Да. Если свойство ТипЗначения не задано, в одном списке могут лежать числа, строки и ссылки вперемешку.
Можно ли записать список значений в реквизит справочника или документа?
Напрямую нет — такого типа реквизита у объектов нет. Используйте тип ХранилищеЗначения или табличную часть.
Передаётся ли список значений между клиентом и сервером?
Да, список значений можно передать параметром серверной процедуры и вернуть из неё. Значения внутри должны быть допустимы на клиенте.
Как получить количество отмеченных элементов?
Обойдите список циклом и посчитайте элементы, у которых Пометка = Истина. Встроенного счётчика пометок нет.
Чем ДоступныеЗначения отличаются от ТипЗначения?
ТипЗначения ограничивает тип, а ДоступныеЗначения — конкретный набор допустимых значений для элементов списка на форме.