В разработке на платформе 1С часто возникает задача добавить в ТаблицуЗначений (ТЗ) служебную колонку с порядковым номером строки. Это может быть необходимо для вывода информации в определенном порядке, для сохранения исходной последовательности строк перед сортировкой или для других алгоритмических целей. На первый взгляд, задача кажется простой, но в ней есть свои нюансы, которые мы и разберем.
Основной вопрос — как программно создать новую колонку, например, с именем "Номер", и заполнить ее значениями, соответствующими индексам строк (0, 1, 2, ...) или порядковым номерам (1, 2, 3, ...).
Это самый распространенный и понятный способ. Процесс состоит из двух шагов: сначала создаем структуру (колонку), а затем заполняем ее данными для каждой строки.
Шаг 1. Добавление новой колонки
Для добавления колонки в ТаблицуЗначений используется метод Колонки.Добавить(). В качестве параметров мы передаем имя новой колонки и, опционально, ее тип. Для порядкового номера лучше всего подходит тип "Число".
// Предположим, у нас есть Таблица Значений с именем МояТЗ
МояТЗ.Колонки.Добавить("НомерСтроки", "Число");
После выполнения этого кода в нашей таблице появится новая, пока еще пустая колонка "НомерСтроки".
Шаг 2. Заполнение колонки номерами
Теперь необходимо перебрать все строки таблицы и для каждой из них записать в новую колонку ее порядковый номер. Рассмотрим два варианта циклов.
Вариант А: Использование цикла Для Каждого
Этот способ является более современным и читаемым. Внутри цикла мы обращаемся к текущей строке и присваиваем ее колонке "НомерСтроки" значение, полученное через метод Индекс(). Метод Индекс() возвращает позицию строки в таблице, начиная с 0.
// Заполнение номерами, начиная с 0 (соответствует индексам)
Для Каждого СтрокаТЗ Из МояТЗ Цикл
СтрокаТЗ.НомерСтроки = МояТЗ.Индекс(СтрокаТЗ);
КонецЦикла;
Часто пользователям удобнее видеть нумерацию, которая начинается с 1. Это легко исправить, просто добавив единицу к индексу.
// Заполнение номерами, начиная с 1
Для Каждого СтрокаТЗ Из МояТЗ Цикл
СтрокаТЗ.НомерСтроки = МояТЗ.Индекс(СтрокаТЗ) + 1;
КонецЦикла;
Вариант Б: Использование цикла со счетчиком Для ... По ...
Классический вариант цикла, который напрямую работает с индексами. Он может быть немного быстрее на очень больших таблицах.
// Заполнение номерами, начиная с 0
Для Индекс = 0 По МояТЗ.Количество() - 1 Цикл
СтрокаТЗ = МояТЗ[Индекс];
СтрокаТЗ.НомерСтроки = Индекс;
КонецЦикла;
Аналогично, для нумерации с единицы просто прибавляем 1 к значению счетчика.
// Заполнение номерами, начиная с 1
Для Индекс = 0 По МояТЗ.Количество() - 1 Цикл
СтрокаТЗ = МояТЗ[Индекс];
СтрокаТЗ.НомерСтроки = Индекс + 1;
КонецЦикла;
На форуме справедливо заметили, что у каждой строки и так есть индекс, который можно получить методом Индекс(). Так зачем же создавать дублирующую информацию? Причин может быть несколько:
ТаблицаЗначений выведена на форму, пользователь может удалять, добавлять и перемещать строки. В этом случае индексы будут динамически меняться, и ссылаться на них станет невозможно. А значение в колонке "НомерСтроки" останется неизменным (если его не пересчитывать принудительно) и может служить "якорем".В ходе обсуждения один из участников привел пример кода, который не работал так, как ожидалось. Разберем его, чтобы понять логику ошибки.
Код выглядел примерно так:
// Неправильный код!
ТЗ2.Колонки.Добавить("НомерСтроки");
Для ЗначениеСтроки = 0 По ТЗ.Количество() - 1 Цикл
Стр = ТЗ2.Добавить();
Стр.НомерСтроки = ЗначениеСтроки;
КонецЦикла;
В чем здесь ошибка?
Этот код не модифицирует исходную таблицу ТЗ. Вместо этого он:
ТЗ2.ТЗ2 новые пустые строки и заполняет только одну колонку "НомерСтроки".В результате мы получаем не исходную таблицу с новой колонкой, а совершенно новую таблицу, содержащую только пронумерованные пустые строки. Правильный подход — работать с одной и той же таблицей, получая существующие строки по индексу и изменяя их, как было показано в решениях выше.
Помимо простого циклического заполнения, стоит рассмотреть и другие сценарии.
Использование уникальных идентификаторов (GUID)
Если задача состоит в том, чтобы надежно идентифицировать каждую строку, даже после удаления, добавления и перемешивания, то простой порядковый номер может не подойти. В этом случае лучше использовать УникальныйИдентификатор.
МояТЗ.Колонки.Добавить("УникальныйИдентификаторСтроки", "УникальныйИдентификатор");
Для Каждого СтрокаТЗ Из МояТЗ Цикл
СтрокаТЗ.УникальныйИдентификаторСтроки = Новый УникальныйИдентификатор();
КонецЦикла;
Такой идентификатор будет уникален для каждой строки и никогда не изменится, что делает его идеальным ключом для связывания данных.
Нумерация для отчетов в СКД
Важный момент: если нумерация строк нужна только для отображения в печатной форме или отчете, который формируется через Систему Компоновки Данных (СКД), то нет необходимости изменять исходную ТаблицуЗначений. В СКД есть встроенные функции, которые делают это "на лету" при формировании отчета.
В вычисляемых полях макета СКД можно использовать функции НомерПоПорядку() или НомерПоПорядкуВГруппировке(). Это более правильный и производительный подход, так как он не требует лишней обработки данных и не изменяет исходный объект.