К статье
Практический материал

Разработка и Конфигурация · 10 мин

Как получить номер строки таблицы значений в 1С

Как получить номер строки таблицы значений в 1С: метод Индекс(), перебор в цикле, поиск по условию. Примеры кода, типичные ошибки и отличия от табличной части.

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

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

Как устроена нумерация строк в таблице значений

Таблица значений — это несохраняемая в базе коллекция строк, которая существует только в оперативной памяти во время выполнения кода. Каждая строка доступна по индексу: первая строка имеет индекс 0, вторая — 1 и так далее. Метод Количество() возвращает общее число строк, поэтому индекс последней строки всегда равен ТЗ.Количество() - 1.

У объекта СтрокаТаблицыЗначений нет встроенного свойства с номером. Это принципиальное отличие от строк табличных частей документов и справочников, где свойство НомерСтроки поддерживается платформой автоматически. Поэтому любой «номер» для таблицы значений — это либо индекс, либо значение, которое разработчик хранит в отдельной колонке самостоятельно.

Способ 1. Метод Индекс() — когда строка уже известна

Если у вас уже есть переменная, содержащая конкретную строку таблицы значений (например, она получена из цикла, поиска или передана в процедуру), самый короткий путь — метод Индекс(). Он возвращает позицию переданной строки в коллекции или -1, если такой строки в таблице нет.

НомерСтроки = ТаблицаТоваров.Индекс(ТекущаяСтрока) + 1;

Сообщить("Товар найден в строке № " + НомерСтроки);

Проверка на -1 обязательна, если строка могла быть получена из другой таблицы или удалена. Частая ошибка — передать в Индекс() строку из копии таблицы: метод вернёт -1, а код без проверки покажет «строку № 0», что введёт в заблуждение.

Способ 2. Перебор в цикле с вычислением номера

Когда номер нужен прямо в процессе обхода таблицы, удобнее не вызывать Индекс() для каждой строки, а считать позицию в самом цикле. Есть два рабочих варианта: классический цикл со счётчиком и цикл «Для Каждого» с ручным накоплением номера.

Для Сч = 0 По ТаблицаТоваров.Количество() - 1 Цикл

СтрокаТЗ = ТаблицаТоваров[Сч];

НомерСтроки = Сч + 1;

// работа со строкой

КонецЦикла;

НомерСтроки = 0;

Для Каждого СтрокаТЗ Из ТаблицаТоваров Цикл

НомерСтроки = НомерСтроки + 1;

// работа со строкой

КонецЦикла;

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

bsl
НомерСтроки = 0;
Для Каждого СтрокаТЗ Из ТаблицаТоваров Цикл
    НомерСтроки = НомерСтроки + 1;
    Если Не ЗначениеЗаполнено(СтрокаТЗ.Цена) Тогда
        Сообщить("Не заполнена цена в строке " + НомерСтроки);
    КонецЕсли;
КонецЦикла;

Способ 3. Получить номер строки, найденной по условию

На практике чаще всего задача звучит так: найти строку с нужным товаром и узнать её номер. Здесь методы Найти() и НайтиСтроки() комбинируются с Индекс(). Найти() возвращает первую подходящую строку или Неопределено, НайтиСтроки() — массив всех подходящих строк.

НайденнаяСтрока = ТаблицаТоваров.Найти(Артикул, "Артикул");

Если НайденнаяСтрока <> Неопределено Тогда

НомерСтроки = ТаблицаТоваров.Индекс(НайденнаяСтрока) + 1;

КонецЕсли;

Если совпадений несколько, обходите массив из НайтиСтроки() и для каждого элемента вызывайте Индекс(). Учтите, что это решение работает за линейное время на каждую строку: на больших таблицах (десятки тысяч строк) многократный вызов Индекс() заметно тормозит выполнение. В таких случаях эффективнее один перебор со счётчиком, где номер фиксируется в момент совпадения условия.

Сравнение вариантов

Индекс(Строка)

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

Счётчик в цикле

Оптимально при обходе всей таблицы: номер известен в каждой итерации без дополнительных поисков.

Колонка НомерСтроки

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

Как сохранить номер строки при сортировке и свёртке

Индекс — это текущая позиция, а не постоянный признак строки. После Сортировать(), Свернуть() или удаления строк позиции пересчитываются, и ранее полученный номер теряет смысл. Если логика требует «привязать» номер к данным, добавьте в таблицу собственную колонку и заполните её один раз сразу после формирования таблицы.

ТаблицаТоваров.Колонки.Добавить("НомерСтроки", Новый ОписаниеТипов("Число"));

Для Сч = 0 По ТаблицаТоваров.Количество() - 1 Цикл

ТаблицаТоваров[Сч].НомерСтроки = Сч + 1;

КонецЦикла;

Такой подход стандартно применяется при загрузке данных из файлов: номер строки исходного файла сохраняют в колонке, чтобы потом в сообщениях об ошибках указывать пользователю, какую именно строку Excel или CSV он должен исправить. Это устойчиво к любым последующим преобразованиям таблицы.

Номер строки на управляемой форме: ДанныеФормыКоллекция

Когда таблица значений выведена на управляемую форму как реквизит, в коде формы вы работаете не с ТаблицаЗначений, а с объектом ДанныеФормыКоллекция. У него тоже есть метод Индекс(), а у текущей строки элемента формы можно получить идентификатор через Элементы.ИмяТаблицы.ТекущаяСтрока.

ТекущиеДанные = Элементы.ТаблицаТоваров.ТекущиеДанные;

Если ТекущиеДанные <> Неопределено Тогда

НомерСтроки = ТаблицаТоваров.Индекс(ТекущиеДанные) + 1;

КонецЕсли;

На форме у строки есть ещё одно свойство — НомерСтроки, которое платформа ведёт автоматически и показывает в строке нумерации табличного поля. Оно совпадает с Индекс() + 1 при отсутствии отбора, но при включённом отборе в табличном поле отображаемый номер и индекс в коллекции могут расходиться. Для программной логики всегда используйте Индекс(), а для сообщений пользователю — тот номер, который он видит на экране.

Типичные ошибки
01
Забыть прибавить единицу к индексу — пользователь видит нумерацию с нуля и не может найти строку в исходных данных.
02
Не проверить результат Найти() на Неопределено — Индекс(Неопределено) вызывает ошибку выполнения.
03
Искать Индекс() строки из копии таблицы — метод возвращает -1, логика срабатывает неверно.
04
Использовать старый номер после сортировки или удаления строк — позиции уже пересчитаны.
05
Путать НомерСтроки табличной части документа с индексом таблицы значений — это разные механизмы.

Проверка результата и отладка

Убедиться, что номер получен правильно, проще всего в отладчике: поставьте точку останова после вычисления, откройте таблицу значений через «Вычислить выражение» (F9 → ТЗ → «Показать значение») и сверьте, что строка с нужными данными действительно стоит на позиции НомерСтроки - 1 по индексу.

Второй контроль — обратное обращение: выражение ТЗ[НомерСтроки - 1] должно вернуть ту же самую строку, с которой вы начинали. Если возвращается другая строка, значит между получением номера и проверкой таблица изменилась. Для сообщений пользователю дополнительно выводите ключевые данные строки (например, наименование товара) рядом с номером — это исключает двойное толкование.

Контрольные точки

Как проверить результат

Значение Индекс()
Норма

Число от 0 до Количество()-1

Тревожный признак

-1 — строка не из этой таблицы

Обратное обращение ТЗ[Номер-1]
Норма

Возвращается исходная строка с теми же данными

Тревожный признак

Другая строка — таблица изменялась после получения номера

Номер в сообщении пользователю
Норма

Совпадает с номером, видимым в файле или на форме

Тревожный признак

Смещение на 1 — забыли прибавить единицу

Часто задаваемые вопросы

Почему у строки таблицы значений нет свойства НомерСтроки?

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

Что вернёт Индекс(), если строки нет в таблице?

Метод вернёт -1. Это штатная ситуация, а не ошибка, поэтому результат всегда проверяют: если индекс меньше нуля, строка не принадлежит данной таблице значений, и дальнейшие вычисления номера проводить нельзя.

Как получить номера всех строк, удовлетворяющих условию?

Используйте НайтиСтроки() с структурой отбора — метод вернёт массив строк. Затем в цикле по массиву для каждой строки вызовите Индекс() и прибавьте единицу. На больших таблицах быстрее один обход всей таблицы со счётчиком и проверкой условия внутри цикла.

Сохранится ли номер строки после сортировки таблицы?

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

Чем отличается номер строки табличной части документа от индекса таблицы значений?

У строк табличной части есть автоматическое свойство НомерСтроки, начинающееся с единицы, — его поддерживает платформа. У таблицы значений такого свойства нет, есть только индекс с нуля. Если вы выгрузили табличную часть в таблицу значений через Выгрузить(), исходные номера сохранятся в одноимённой колонке, но обновлять их придётся вручную.

Как узнать номер текущей строки таблицы на управляемой форме?

Получите ТекущиеДанные элемента формы и передайте их в метод Индекс() реквизита-коллекции, прибавив единицу. Либо используйте свойство НомерСтроки текущих данных — но помните, что при включённом отборе в табличном поле отображаемый номер и индекс в коллекции могут различаться.

Итог

Что важно запомнить

Номер строки таблицы значений — это Индекс(Строка) + 1. Всегда проверяйте результат Найти() на Неопределено и результат Индекс() на -1. При обходе таблицы используйте счётчик в цикле, а если номер должен пережить сортировку или свёртку — храните его в отдельной колонке.