Колонка таблицы значений в список значений: способы на встроенном языке 1С
Содержание
Задача знакома любому программисту 1С: в таблице значений лежат сотни строк, а в форму или в параметр выбора нужен список значений из одной колонки. Например, коды номенклатуры, чтобы показать их в выпадающем списке, или контрагенты, найденные запросом.
Короткий ответ: выгрузите колонку в массив методом ВыгрузитьКолонку() и загрузите массив в список методом ЗагрузитьЗначения(). Две строки кода вместо цикла. Ниже: как это работает, чем отличается от перебора строк, как оставить только уникальные значения и что делать, если нужны ещё и представления.
Из чего состоят два объекта и почему между ними нужен массив
Таблица значений (ТаблицаЗначений) — это строки и именованные колонки. В колонке может лежать любой тип: число, строка, дата, ссылка. Тип колонки задаётся при её создании, а может быть не задан вовсе.
Список значений (СписокЗначений) устроен иначе. Это одномерная коллекция элементов. У каждого элемента есть:
- 🔹 значение (любого типа);
- 🔹 представление — строка, которую видит пользователь;
- 🔹 пометка — флажок для списков с галочками;
- 🔹 картинка, если список выводится с иконками.
Прямого метода «колонка таблицы → список» в платформе нет. Зато есть два метода-«переходника», и мостом служит массив:
| Объект | Метод | Что делает |
|---|---|---|
ТаблицаЗначений | ВыгрузитьКолонку(Колонка) | Возвращает массив значений колонки |
СписокЗначений | ЗагрузитьЗначения(Массив) | Заменяет содержимое списка значениями массива |
СписокЗначений | ВыгрузитьЗначения() | Обратная операция: список → массив |
Массив | Добавить(Значение) | Добавляет значение в конец |
Колонка в ВыгрузитьКолонку() можно передать тремя способами: именем колонки строкой, индексом (с нуля) или самим объектом колонки. Чаще всего пишут именем.
Быстрый способ: ВыгрузитьКолонку и ЗагрузитьЗначения
Допустим, в таблице ТаблицаТоваров есть колонка Артикул. Нужен список артикулов:
МассивАртикулов = ТаблицаТоваров.ВыгрузитьКолонку("Артикул");
СписокАртикулов = Новый СписокЗначений;
СписокАртикулов.ЗагрузитьЗначения(МассивАртикулов);
Это весь код. Строки таблицы переносятся в том же порядке, в каком идут в таблице. Количество элементов списка равно количеству строк, в том числе повторяющиеся значения сохраняются.
ЗагрузитьЗначения() сначала очищает список, а потом заполняет. Если в списке уже были элементы, они пропадут. Хотите дописать значения к существующим — используйте цикл (см. ниже) или объедините массивы заранее.
Ещё один момент: представление у загруженных элементов будет пустым. Список в форме при этом покажет само значение. Для строк и чисел это незаметно. Для ссылок платформа выведет представление объекта, то есть наименование или номер документа. Явно задавать представление нужно, только если оно должно отличаться от значения.
💡 Если тип значений в списке важен (например, в выпадающем списке реквизита формы), задайте его заранее: СписокАртикулов.ТипЗначения = Новый ОписаниеТипов("Строка");. Тогда пользователь не сможет вписать в список элемент другого типа.
Перебор строк в цикле: когда без него не обойтись
Цикл нужен в трёх случаях: надо задать представление, надо отфильтровать строки или надо дописать значения к уже заполненному списку.
СписокТоваров = Новый СписокЗначений;
Для Каждого Строка Из ТаблицаТоваров Цикл
Если Строка.Количество > 0 Тогда
СписокТоваров.Добавить(Строка.Артикул, Строка.Наименование);
КонецЕсли;
КонецЦикла;
Здесь Добавить(Значение, Представление) кладёт в список артикул, а пользователю показывает наименование. Строки с нулевым количеством в список не попадают.
Третий параметр метода Добавить() — пометка. Если список будет выводиться с флажками, передайте Истина или Ложь:
СписокТоваров.Добавить(Строка.Артикул, Строка.Наименование, Истина);
Сравните подходы:
| Способ | Строк кода | Представление | Фильтр | Дописывает в готовый список |
|---|---|---|---|---|
ВыгрузитьКолонку + ЗагрузитьЗначения | 2 | нет | нет | нет, заменяет |
Цикл Для Каждого | 4–6 | да | да | да |
Запрос с РАЗЛИЧНЫЕ | 6–10 | нет | да, в условии | нет |
Только уникальные значения
Выгрузка колонки «как есть» сохраняет дубли. Если в таблице пять строк с одним и тем же контрагентом, он окажется в списке пять раз. Для выпадающего списка выбора это обычно не нужно. Есть три рабочих приёма.
Свёртка таблицы
Метод Свернуть() схлопывает строки с одинаковым значением ключевых колонок. Работайте с копией, иначе испортите исходную таблицу:
КопияТаблицы = ТаблицаТоваров.Скопировать();
КопияТаблицы.Свернуть("Контрагент");
СписокКонтрагентов = Новый СписокЗначений;
СписокКонтрагентов.ЗагрузитьЗначения(КопияТаблицы.ВыгрузитьКолонку("Контрагент"));
Первый параметр Свернуть() — колонки, по которым ищутся одинаковые строки. Второй (необязательный) — колонки, которые нужно суммировать. Остальные колонки из копии исчезнут, что нам и нужно: остаётся одна колонка с уникальными значениями.
Проверка перед добавлением
Если таблица маленькая, а свёртка кажется избыточной, проверьте наличие значения прямо в цикле:
СписокКонтрагентов = Новый СписокЗначений;
Для Каждого Строка Из ТаблицаТоваров Цикл
Если СписокКонтрагентов.НайтиПоЗначению(Строка.Контрагент) = Неопределено Тогда
СписокКонтрагентов.Добавить(Строка.Контрагент);
КонецЕсли;
КонецЦикла;
НайтиПоЗначению() возвращает элемент списка или Неопределено, если такого значения нет. Поиск линейный, поэтому на больших объёмах такой способ медленный. Для нескольких сотен строк разницы не заметите.
Соответствие как «множество»
Когда строк десятки тысяч, быстрее завести Соответствие: ключ — значение, а проверка наличия ключа делается за постоянное время.
Уникальные = Новый Соответствие;
СписокКонтрагентов = Новый СписокЗначений;
Для Каждого Строка Из ТаблицаТоваров Цикл
Если Уникальные[Строка.Контрагент] = Неопределено Тогда
Уникальные.Вставить(Строка.Контрагент, Истина);
СписокКонтрагентов.Добавить(Строка.Контрагент);
КонецЕсли;
КонецЦикла;
Порядок элементов в списке сохраняется как в таблице: соответствие используется только для проверки.
Если выгрузка идёт большими объёмами
На сотнях строк любой способ отработает мгновенно. Заметная разница появляется на десятках тысяч строк и выше.
- ⚡
ВыгрузитьКолонку()+ЗагрузитьЗначения()— самый быстрый вариант: обе операции выполняются внутри платформы, без интерпретации вашего цикла. - 🐢 Цикл с
НайтиПоЗначению()на каждой итерации растёт квадратично: чем больше список, тем дольше поиск. - 🧠 Цикл с
Соответствиерастёт почти линейно, но тратит память на второй объект.
Практическое правило: если представление и фильтр не нужны, берите связку из двух методов. Если нужна уникальность — Свернуть() на копии, а потом те же два метода. Цикл оставляйте для случаев, где без него нельзя.
Не стройте список значений ради одной проверки «есть ли значение». Для этого достаточно массива и метода Найти() либо соответствия. Список значений нужен там, где его будет видеть пользователь или где нужны представления и пометки.
Отдельно про клиент-серверный вызов. Список значений передаётся между клиентом и сервером как обычный объект, а вот таблица значений в форме обработки может быть реквизитом формы (тип ТаблицаЗначений в реквизите — это ДанныеФормыКоллекция). У такого реквизита метода ВыгрузитьКолонку() нет: сначала получите настоящую таблицу методом ПолучитьЭлементы() или выгрузите реквизит через РеквизитФормыВЗначение("ИмяРеквизита") на сервере. Ошибка на этом месте — одна из самых частых.
Типы данных: что окажется в списке и как это учесть
Значения в списке сохраняют тот тип, который был в колонке. Строка остаётся строкой, дата — датой, ссылка — ссылкой. Никакого автоматического приведения к строке не происходит.
Из этого вытекают практические последствия.
- 🔹 Смешанные типы. Если колонка не типизирована и в разных строках лежат число и строка, в списке они так и будут лежать вперемешку. Сортировка такого списка по значению может дать неожиданный порядок, потому что сравнение значений разных типов ведётся по внутренним правилам платформы.
- 🔹 Пустые значения. Строки с пустой ссылкой, пустой строкой или
Неопределенотоже попадут в список. Для выпадающего списка пустой элемент обычно лишний. - 🔹 Ссылки. Элемент хранит ссылку, а не её текст. Представление ссылки платформа вычисляет сама при показе.
Если пустые значения не нужны, отфильтруйте их циклом:
Для Каждого Строка Из ТаблицаТоваров Цикл
Если ЗначениеЗаполнено(Строка.Артикул) Тогда
СписокАртикулов.Добавить(Строка.Артикул);
КонецЕсли;
КонецЦикла;
Если же нужно привести всё к одному типу, например, к строке для показа пользователю, преобразуйте значение явно функцией Строка(Значение). Не называйте переменную цикла Строка: она перекроет одноимённую функцию, и вызов Строка(...) внутри цикла перестанет работать, лучше СтрокаТаблицы. Для чисел с форматированием используйте Формат(Значение, "ЧГ=0"): так число не разобьётся на группы разрядов пробелами.
Для отсортированного списка есть готовые методы:
СписокАртикулов.СортироватьПоЗначению(НаправлениеСортировки.Возр);
Сортировать по представлению можно методом СортироватьПоПредставлению().
Когда колонку проще получить запросом
Если таблица значений получена из запроса, нет смысла сначала выгружать её целиком, а потом сворачивать. Уникальность и фильтр можно сделать на стороне запроса:
Запрос = Новый Запрос;
Запрос.Текст =
"ВЫБРАТЬ РАЗЛИЧНЫЕ
| Товары.Артикул КАК Артикул
|ИЗ
| Справочник.Номенклатура КАК Товары
|ГДЕ
| НЕ Товары.ЭтоГруппа
| И Товары.Артикул <> """"";
Результат = Запрос.Выполнить();
СписокАртикулов = Новый СписокЗначений;
СписокАртикулов.ЗагрузитьЗначения(Результат.Выгрузить().ВыгрузитьКолонку("Артикул"));
Ключевое слово РАЗЛИЧНЫЕ убирает дубли в самой базе, а условие ГДЕ отсекает группы и пустые артикулы. До прикладного кода доходят уже чистые данные.
Запросом можно обработать и таблицу значений, которая лежит в памяти. Передайте её параметром и обратитесь к ней во временной таблице или напрямую в ИЗ &Таблица. Такой приём оправдан, когда данные нужно соединить с таблицами базы, сгруппировать или отфильтровать условиями, которые громоздко писать циклом.
Есть и короткий путь без промежуточной таблицы: у результата запроса тоже есть метод Выгрузить(), а у полученной таблицы — ВыгрузитьКолонку(). Поэтому цепочка Результат.Выгрузить().ВыгрузитьКолонку("Артикул") из примера выше самодостаточна.
Если запрос может вернуть очень много строк, а нужна только часть, ограничьте выборку на стороне запроса (ПЕРВЫЕ N). Выгружать в память миллион строк ради десяти элементов списка — плохая идея.
Ещё одна деталь про выбор имени переменной цикла. В примерах выше она названа коротко ради читаемости, а в рабочем коде удобнее СтрокаТаблицы. Тогда ни функция Строка(), ни другие встроенные имена не окажутся перекрытыми, а код проще читать тому, кто будет его сопровождать.
Типичные ошибки
Разберём то, на чём спотыкаются чаще всего.
«Поле объекта не обнаружено» при ВыгрузитьКолонку
Имя колонки написано с опечаткой или регистр и язык не совпадают с тем, под каким колонка создана. Платформа к регистру нечувствительна, но латинская «a» и русская «а» — разные символы. Проверьте имя через ТаблицаТоваров.Колонки — переберите коллекцию и выведите имена.
Список пустой после загрузки
Проверьте, что таблица вообще заполнена: ТаблицаТоваров.Количество(). Часто причина в том, что выгрузка выполнена раньше, чем таблица наполнилась, либо вы работаете с копией, а не с рабочей таблицей.
Потеряны прежние элементы
Вы вызвали ЗагрузитьЗначения() на непустом списке. Метод заменяет содержимое. Нужно дописать — перебирайте массив циклом и вызывайте Добавить().
Метод не найден у реквизита формы
Реквизит формы типа «Таблица значений» хранится как ДанныеФормыКоллекция, и методов таблицы значений у неё нет. Обратите внимание: это ограничение именно формы. Решение описано выше, в разделе про большие объёмы.
Дубли в выпадающем списке
Список строился прямой выгрузкой колонки. Примените свёртку на копии таблицы или проверку перед добавлением.
Список не показывает ожидаемый текст
Представление не задано. Загрузка через ЗагрузитьЗначения() представлений не создаёт. Заполните их циклом или присвойте элементам вручную: Элемент.Представление = "Текст".
Частые вопросы
Можно ли выгрузить две колонки сразу — значение и представление?
Список.Добавить(Строка.Код, Строка.Наименование). Метод ЗагрузитьЗначения() принимает один массив и представление не заполняет.Влияет ли выгрузка на исходную таблицу значений?
ВыгрузитьКолонку() читает данные и возвращает новый массив. Исходная таблица остаётся как была. Менять её будет только Свернуть(), поэтому вызывайте его на копии.Чем список значений отличается от массива, если оба хранят одномерный набор?
Как получить из списка значений обратно массив?
ВыгрузитьЗначения(). Он возвращает массив значений элементов, представления отбрасываются.Как выгрузить значения из колонки табличной части документа?
ВыгрузитьКолонку(): Документ.Товары.ВыгрузитьКолонку("Номенклатура"). Дальше загрузка в список — как обычно.