СписокЗначений во встроенном языке 1С 8.3: от конструктора до формы
Содержание
Список значений в 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 меняет и исходный список. Это частая причина «загадочных» багов, когда функция портит переданный ей параметр. Если процедура не должна менять входной список, работайте с копией.