Столбец для массива в 1С: таблица значений, массив массивов, табличный документ
Содержание
У объекта Массив в 1С нет столбцов: это одномерный список значений, у него только индекс и содержимое. Чтобы получить столбцы, берут ТаблицаЗначений и добавляют колонки методом Колонки.Добавить(). Если данные уже лежат в массиве, их загружают в новую колонку одной строкой через ЗагрузитьКолонку().
Запрос «добавить столбец в массив» на практике означает одну из трёх задач: нужна двумерная структура «строки × поля», нужно дописать поле к уже заполненной таблице или нужен лишний столбец в печатной форме. Ниже по каждой задаче свой способ и рабочий код. Примеры написаны для платформы 8.3 и выполняются на сервере и на клиенте.
Почему у массива нет столбцов и что брать вместо него
Массив хранит элементы по порядку: индексы идут с нуля, Массив[0], Массив[1] и так далее. Добавить к нему «ещё одно измерение» методом платформы нельзя. Можно только имитировать двумерность разными коллекциями.
Выбор зависит от того, что вы делаете с данными дальше:
| Коллекция | Когда подходит | Ограничения |
|---|---|---|
ТаблицаЗначений | Нужны именованные столбцы, сортировка, свёртка, поиск, вывод в форму | Тяжелее массива по памяти, на миллионах строк заметно |
| Массив массивов | Небольшой расчёт внутри процедуры, имён полей не надо | Нет имён колонок, легко запутаться в индексах |
| Массив структур | Каждая «строка» — набор именованных свойств | Нет встроенной сортировки и свёртки |
ТабличныйДокумент | Результат нужно показать или напечатать | Это не коллекция для вычислений, а форма вывода |
Для большинства задач с вычислениями правильный ответ — таблица значений. Остальные варианты разберём ниже.
Если вам нужен просто список с подписями (значение и представление), смотрите в сторону СписокЗначений: у него два «столбца» из коробки.
Когда столбцы вообще не нужны
Бывает, что двумерная структура появляется по привычке. Если вы храните пары «ключ — значение», достаточно Соответствие: Соответствие.Вставить("Бумага А4", 10), а читать можно по ключу, без поиска по индексу. Если нужен просто список уникальных значений, хватит массива и проверки через Найти() перед добавлением.
Столбцы нужны, когда у каждого элемента несколько характеристик одновременно и с ними предстоит работать как с набором: сортировать, группировать, выводить в таблицу на форме. Для остальных задач таблица значений только усложнит код.
Практичное правило: если в коде появилось два параллельных массива с одинаковым числом элементов («наименования» и «количества»), пора переходить на таблицу значений. Параллельные массивы расходятся при первой же правке: удалили элемент в одном, забыли во втором, и данные поехали.
Первый способ: создаём таблицу значений и добавляем колонки
Это основной путь. Таблица значений создаётся пустой, колонки описываются явно, потом идёт заполнение строк.
Таблица = Новый ТаблицаЗначений;
Таблица.Колонки.Добавить("Номенклатура");
Таблица.Колонки.Добавить("Количество", Новый ОписаниеТипов("Число", , , Новый КвалификаторыЧисла(15, 3)));
Таблица.Колонки.Добавить("Сумма", Новый ОписаниеТипов("Число", , , Новый КвалификаторыЧисла(15, 2)));
Строка = Таблица.Добавить();
Строка.Номенклатура = "Бумага А4";
Строка.Количество = 10;
Строка.Сумма = 1250;
Метод Колонки.Добавить() принимает четыре параметра: имя, тип, заголовок и ширину. Обязательно только имя. Остальные задают, когда таблица потом выводится на форму.
Имя колонки и тип
Имя колонки должно быть допустимым идентификатором: без пробелов и спецсимволов, не начинается с цифры. Заголовок можно писать любой, в нём пробелы разрешены.
Тип лучше указывать сразу. Без типа в колонку попадёт что угодно, а сортировка и свёртка по смешанным значениям работают непредсказуемо. Строки и даты описывают через Новый ОписаниеТипов("Строка") и Новый ОписаниеТипов("Дата"), ссылки — через Новый ОписаниеТипов("СправочникСсылка.Номенклатура").
Второй способ: выгрузить массив в столбец существующей таблицы
Частый случай: массив уже собран, например список сумм, и его нужно положить в колонку. Руками по строкам делать не надо.
Суммы = Новый Массив;
Суммы.Добавить(1250);
Суммы.Добавить(300);
Суммы.Добавить(75.5);
Таблица = Новый ТаблицаЗначений;
Таблица.Колонки.Добавить("Номер");
Таблица.Колонки.Добавить("Сумма");
Для Счетчик = 1 По Суммы.Количество() Цикл
Таблица.Добавить().Номер = Счетчик;
КонецЦикла;
Таблица.ЗагрузитьКолонку(Суммы, "Сумма");
Метод ЗагрузитьКолонку(Массив, Колонка) кладёт элементы по порядку, начиная с первой строки. Если элементов в массиве меньше, чем строк, остальные ячейки не затрагиваются. Если больше — лишние отбрасываются: новых строк метод не создаёт.
Обратная операция — ВыгрузитьКолонку("Сумма"). Она возвращает массив со значениями одной колонки. Так удобно передавать список в запрос как параметр для условия В (&Список).
Количество строк таблицы должно совпадать с размером массива. Сначала создайте строки, потом загружайте колонку. Иначе часть данных молча пропадёт.
Третий способ: добавить колонку в готовую таблицу и посчитать её
Таблица уже есть, например из результата запроса: Результат.Выгрузить(). Нужна ещё одна колонка с расчётом.
Таблица.Колонки.Добавить("Цена", Новый ОписаниеТипов("Число", , , Новый КвалификаторыЧисла(15, 2)));
Для Каждого Строка Из Таблица Цикл
Если Строка.Количество <> 0 Тогда
Строка.Цена = Строка.Сумма / Строка.Количество;
КонецЕсли;
КонецЦикла;
Новая колонка встаёт в конец. Если порядок важен для вывода на форму, используйте Колонки.Вставить(Индекс, Имя, Тип, Заголовок): колонка встанет на указанную позицию, а остальные сдвинутся.
Проверка, что колонки ещё нет
Повторное добавление колонки с тем же именем вызывает исключение. Если таблица приходит из внешнего источника, проверяйте заранее:
Если Таблица.Колонки.Найти("Цена") = Неопределено Тогда
Таблица.Колонки.Добавить("Цена");
КонецЕсли;
Удаляется колонка командой Таблица.Колонки.Удалить("Цена"). Данные в ней пропадут вместе с колонкой.
Колонка из результата запроса
Таблицу значений чаще всего получают из запроса. Колонки в ней уже есть, по одной на каждое выбранное поле.
Запрос = Новый Запрос;
Запрос.Текст = "ВЫБРАТЬ
| Номенклатура.Наименование КАК Наименование,
| Номенклатура.Артикул КАК Артикул
|ИЗ
| Справочник.Номенклатура КАК Номенклатура";
Таблица = Запрос.Выполнить().Выгрузить();
Таблица.Колонки.Добавить("Метка", Новый ОписаниеТипов("Строка"));
Таблица.ЗаполнитьЗначения("не проверено", "Метка");
Метод ЗаполнитьЗначения(Значение, Колонка) ставит одно и то же значение во всех строках колонки. Для служебных пометок и флагов это быстрее цикла.
Копия структуры без данных
Иногда нужна таблица с теми же колонками, но пустая, например чтобы собрать в неё отфильтрованные строки:
Отбор = Таблица.СкопироватьКолонки();
Для Каждого Строка Из Таблица Цикл
Если Строка.Метка = "не проверено" Тогда
НоваяСтрока = Отбор.Добавить();
ЗаполнитьЗначенияСвойств(НоваяСтрока, Строка);
КонецЕсли;
КонецЦикла;
СкопироватьКолонки() переносит имена, типы и заголовки. Строки не копируются. Для копии вместе с данными вызывайте Скопировать(); там же можно сразу выбрать нужные колонки второй строкой параметров.
Перебор колонок
Если структура таблицы заранее неизвестна, например пришла из внешнего файла, колонки обходят циклом и читают имя каждой:
Для Каждого Колонка Из Таблица.Колонки Цикл
Сообщить(Колонка.Имя + " (" + Колонка.Заголовок + ")");
КонецЦикла;
Так же удобно собирать таблицу «на лету»: прочитали заголовки из первой строки файла, по ним создали колонки, дальше заполняем строки.
Четвёртый способ: массив массивов и массив структур
Таблица значений избыточна, когда данных на пару десятков строк и они нужны одной процедуре. Тогда делают массив, элементы которого тоже массивы: внешний — строки, внутренний — столбцы.
Данные = Новый Массив;
Строка = Новый Массив;
Строка.Добавить("Бумага А4");
Строка.Добавить(10);
Данные.Добавить(Строка);
Строка = Новый Массив;
Строка.Добавить("Картридж");
Строка.Добавить(2);
Данные.Добавить(Строка);
// Добавляем «столбец» — третий элемент в каждую строку
Для Каждого Строка Из Данные Цикл
Строка.Добавить(Строка[1] * 100);
КонецЦикла;
Каждая строка — отдельный массив, поэтому в цикле достаточно дописать элемент в конец. Столбец «Количество» тут лежит по индексу 1, и помнить это придётся самому.
Читаемее вариант со структурами:
Данные = Новый Массив;
Элемент = Новый Структура("Номенклатура, Количество", "Бумага А4", 10);
Данные.Добавить(Элемент);
Для Каждого Элемент Из Данные Цикл
Элемент.Вставить("Сумма", Элемент.Количество * 125);
КонецЦикла;
Метод Структура.Вставить() добавляет новое свойство или меняет существующее. Это и есть «добавить столбец»: поле появляется у каждого элемента. Минус — массив структур не умеет сортироваться и сворачиваться, придётся писать цикл самому.
Пятый вариант: столбец в табличном документе
Если вы формируете печатную форму или отчёт, речь о ТабличныйДокумент. Здесь «столбец» — это колонка ячеек, у которой есть ширина и содержимое. Вставить колонку в середину нельзя, обычный путь — дописать справа или присоединить готовую область.
ТабДок = Новый ТабличныйДокумент;
ТабДок.Область(1, 1).Текст = "Номенклатура";
ТабДок.Область(1, 2).Текст = "Количество";
ТабДок.Область(2, 1).Текст = "Бумага А4";
ТабДок.Область(2, 2).Текст = 10;
// Новый столбец справа от существующих
ТабДок.Область(1, 3).Текст = "Сумма";
ТабДок.Область(2, 3).Текст = 1250;
ТабДок.Область(1, 3, 2, 3).ШиринаКолонки = 18;
Область(Строка, Колонка) берёт одну ячейку, Область(СтрокаНачало, КолонкаНачало, СтрокаКонец, КолонкаКонец) — диапазон. Свойство ШиринаКолонки задают у диапазона из нужных столбцов.
Для макетов обычно работают иначе: в макете есть область с шапкой и область со строкой, документ собирают через Вывести(), а горизонтальное расширение делают методом Присоединить(), который ставит область справа от последней выведенной.
Если тот же результат нужен и в таблице значений, и на печать, сначала соберите данные в таблицу значений, а потом выводите её в табличный документ циклом. Считать внутри ячеек табличного документа не стоит.
Скорость: что делать, когда строк много
На сотне строк разницы между способами нет. На десятках тысяч начинается.
- 📌 Колонки добавляйте один раз до заполнения, а не в цикле по строкам.
- 📌 Для расчёта по всей таблице пользуйтесь свёрткой
Свернуть("Номенклатура", "Сумма")вместо ручного суммирования циклом. - 📌 Если колонку можно получить на стороне запроса (
ВЫБРАТЬ ... КАК Цена), делайте это там. Запрос посчитает быстрее, чем цикл на клиенте. - 📌 Не обращайтесь к
Таблица.Колонки.Найти()внутри цикла по строкам. Результат сохраните в переменную. - 📌 Для поиска по значению колонки создайте индекс:
Таблица.Индексы.Добавить("Номенклатура"). ТогдаНайтиСтроки()перестанет перебирать всю таблицу.
Ещё одна ловушка касается типов чисел. Колонка без квалификатора принимает любое число, но при выводе в форму 1С покажет его с настройками по умолчанию. Для денег задавайте 15 знаков и 2 после запятой, для количества 15 и 3. Тогда значения не уедут в экспоненциальную запись и не округлятся на выводе.
Сортировка тоже зависит от колонки. Таблица.Сортировать("Сумма Убыв, Номенклатура") упорядочит строки по убыванию суммы, а при равенстве суммы по имени. Если в колонке лежат значения разных типов, порядок получится странным: числа, строки и даты сравниваются по правилам платформы, а не по здравому смыслу.
Передавая таблицу с клиента на сервер, учтите: она сериализуется целиком. Лишние колонки тоже едут по сети, поэтому ненужные удаляйте до вызова.
Типичные ошибки при добавлении столбцов
Четыре сообщения, которые встречаются чаще остальных.
Таблица.Колонки.Найти("Цена"). Регистр букв не важен, а раскладка важна: латинская «C» вместо кириллической «С» на глаз не отличается, увидите её только в отладчике.Колонки.Добавить() вызвали повторно, например при втором проходе по циклу. Вынесите добавление за цикл или проверьте наличие колонки через Найти().Строка[2] у массива из двух элементов. Индексы идут от нуля, последний элемент — Количество() - 1, или ВГраница().Найти(), который вернул Неопределено. Проверяйте результат перед обращением.Частые вопросы
Можно ли добавить колонку в обычный массив?
Как узнать, сколько колонок в таблице значений?
Таблица.Колонки.Количество(). Имена колонок получают перебором коллекции Для Каждого Колонка Из Таблица.Колонки Цикл, у каждой колонки есть свойство Имя.Как поменять тип колонки уже заполненной таблицы?
Колонки.Удалить().Можно ли выгрузить колонку таблицы значений обратно в массив?
Таблица.ВыгрузитьКолонку("Сумма") возвращает массив значений этой колонки в порядке строк.