Разработка и Конфигурация · 10 мин
Как получить номер строки таблицы значений в 1С
Как получить номер строки таблицы значений в 1С: метод Индекс(), перебор в цикле, поиск по условию. Примеры кода, типичные ошибки и отличия от табличной части.
Получить номер строки таблицы значений — типовая задача при доработке конфигураций 1С: она возникает при поиске нужной записи, синхронизации двух таблиц, выводе сообщений пользователю с указанием позиции ошибки или при построении отчётов. У самой строки таблицы значений нет свойства «НомерСтроки», как у строк табличных частей документов, поэтому номер получают косвенно — через индекс строки в коллекции.
Ключевой момент, который нужно понимать сразу: индексы в коллекциях 1С начинаются с нуля, а пользователи привыкли к нумерации с единицы. Поэтому почти всегда к полученному индексу прибавляют единицу, прежде чем показать номер в сообщении или записать в реквизит. Ниже разобраны все рабочие способы: метод Индекс(), перебор с вычислением позиции, поиск по условию и особенности для управляемых форм.
Как устроена нумерация строк в таблице значений
Таблица значений — это несохраняемая в базе коллекция строк, которая существует только в оперативной памяти во время выполнения кода. Каждая строка доступна по индексу: первая строка имеет индекс 0, вторая — 1 и так далее. Метод Количество() возвращает общее число строк, поэтому индекс последней строки всегда равен ТЗ.Количество() - 1.
У объекта СтрокаТаблицыЗначений нет встроенного свойства с номером. Это принципиальное отличие от строк табличных частей документов и справочников, где свойство НомерСтроки поддерживается платформой автоматически. Поэтому любой «номер» для таблицы значений — это либо индекс, либо значение, которое разработчик хранит в отдельной колонке самостоятельно.
Способ 1. Метод Индекс() — когда строка уже известна
Если у вас уже есть переменная, содержащая конкретную строку таблицы значений (например, она получена из цикла, поиска или передана в процедуру), самый короткий путь — метод Индекс(). Он возвращает позицию переданной строки в коллекции или -1, если такой строки в таблице нет.
НомерСтроки = ТаблицаТоваров.Индекс(ТекущаяСтрока) + 1;
Сообщить("Товар найден в строке № " + НомерСтроки);
Проверка на -1 обязательна, если строка могла быть получена из другой таблицы или удалена. Частая ошибка — передать в Индекс() строку из копии таблицы: метод вернёт -1, а код без проверки покажет «строку № 0», что введёт в заблуждение.
Способ 2. Перебор в цикле с вычислением номера
Когда номер нужен прямо в процессе обхода таблицы, удобнее не вызывать Индекс() для каждой строки, а считать позицию в самом цикле. Есть два рабочих варианта: классический цикл со счётчиком и цикл «Для Каждого» с ручным накоплением номера.
Для Сч = 0 По ТаблицаТоваров.Количество() - 1 Цикл
СтрокаТЗ = ТаблицаТоваров[Сч];
НомерСтроки = Сч + 1;
// работа со строкой
КонецЦикла;
НомерСтроки = 0;
Для Каждого СтрокаТЗ Из ТаблицаТоваров Цикл
НомерСтроки = НомерСтроки + 1;
// работа со строкой
КонецЦикла;
Второй вариант читается легче и не привязан к индексам, но помните: если внутри цикла строки удаляются, счётчик продолжит расти, а фактические позиции сместятся. При удалении строк в цикле безопаснее идти с конца таблицы к началу или собирать строки на удаление в отдельный массив.
НомерСтроки = 0;
Для Каждого СтрокаТЗ Из ТаблицаТоваров Цикл
НомерСтроки = НомерСтроки + 1;
Если Не ЗначениеЗаполнено(СтрокаТЗ.Цена) Тогда
Сообщить("Не заполнена цена в строке " + НомерСтроки);
КонецЕсли;
КонецЦикла;Способ 3. Получить номер строки, найденной по условию
На практике чаще всего задача звучит так: найти строку с нужным товаром и узнать её номер. Здесь методы Найти() и НайтиСтроки() комбинируются с Индекс(). Найти() возвращает первую подходящую строку или Неопределено, НайтиСтроки() — массив всех подходящих строк.
НайденнаяСтрока = ТаблицаТоваров.Найти(Артикул, "Артикул");
Если НайденнаяСтрока <> Неопределено Тогда
НомерСтроки = ТаблицаТоваров.Индекс(НайденнаяСтрока) + 1;
КонецЕсли;
Если совпадений несколько, обходите массив из НайтиСтроки() и для каждого элемента вызывайте Индекс(). Учтите, что это решение работает за линейное время на каждую строку: на больших таблицах (десятки тысяч строк) многократный вызов Индекс() заметно тормозит выполнение. В таких случаях эффективнее один перебор со счётчиком, где номер фиксируется в момент совпадения условия.
Сравнение вариантов
Подходит, когда строка уже получена. Быстро для разового вызова, но медленно при массовом применении на больших таблицах.
Оптимально при обходе всей таблицы: номер известен в каждой итерации без дополнительных поисков.
Подходит, когда номер должен сохраняться при сортировке и свёртке таблицы. Требует заполнения вручную.
Как сохранить номер строки при сортировке и свёртке
Индекс — это текущая позиция, а не постоянный признак строки. После Сортировать(), Свернуть() или удаления строк позиции пересчитываются, и ранее полученный номер теряет смысл. Если логика требует «привязать» номер к данным, добавьте в таблицу собственную колонку и заполните её один раз сразу после формирования таблицы.
ТаблицаТоваров.Колонки.Добавить("НомерСтроки", Новый ОписаниеТипов("Число"));
Для Сч = 0 По ТаблицаТоваров.Количество() - 1 Цикл
ТаблицаТоваров[Сч].НомерСтроки = Сч + 1;
КонецЦикла;
Такой подход стандартно применяется при загрузке данных из файлов: номер строки исходного файла сохраняют в колонке, чтобы потом в сообщениях об ошибках указывать пользователю, какую именно строку Excel или CSV он должен исправить. Это устойчиво к любым последующим преобразованиям таблицы.
Номер строки на управляемой форме: ДанныеФормыКоллекция
Когда таблица значений выведена на управляемую форму как реквизит, в коде формы вы работаете не с ТаблицаЗначений, а с объектом ДанныеФормыКоллекция. У него тоже есть метод Индекс(), а у текущей строки элемента формы можно получить идентификатор через Элементы.ИмяТаблицы.ТекущаяСтрока.
ТекущиеДанные = Элементы.ТаблицаТоваров.ТекущиеДанные;
Если ТекущиеДанные <> Неопределено Тогда
НомерСтроки = ТаблицаТоваров.Индекс(ТекущиеДанные) + 1;
КонецЕсли;
На форме у строки есть ещё одно свойство — НомерСтроки, которое платформа ведёт автоматически и показывает в строке нумерации табличного поля. Оно совпадает с Индекс() + 1 при отсутствии отбора, но при включённом отборе в табличном поле отображаемый номер и индекс в коллекции могут расходиться. Для программной логики всегда используйте Индекс(), а для сообщений пользователю — тот номер, который он видит на экране.
Проверка результата и отладка
Убедиться, что номер получен правильно, проще всего в отладчике: поставьте точку останова после вычисления, откройте таблицу значений через «Вычислить выражение» (F9 → ТЗ → «Показать значение») и сверьте, что строка с нужными данными действительно стоит на позиции НомерСтроки - 1 по индексу.
Второй контроль — обратное обращение: выражение ТЗ[НомерСтроки - 1] должно вернуть ту же самую строку, с которой вы начинали. Если возвращается другая строка, значит между получением номера и проверкой таблица изменилась. Для сообщений пользователю дополнительно выводите ключевые данные строки (например, наименование товара) рядом с номером — это исключает двойное толкование.
Как проверить результат
Число от 0 до Количество()-1
-1 — строка не из этой таблицы
Возвращается исходная строка с теми же данными
Другая строка — таблица изменялась после получения номера
Совпадает с номером, видимым в файле или на форме
Смещение на 1 — забыли прибавить единицу
Часто задаваемые вопросы
Почему у строки таблицы значений нет свойства НомерСтроки?
Таблица значений — временная коллекция в памяти, и платформа не ведёт для неё автоматическую нумерацию, в отличие от табличных частей объектов базы данных. Позиция строки определяется только её текущим индексом, который меняется при сортировке и удалении. Если постоянный номер нужен, его хранят в отдельной колонке.
Что вернёт Индекс(), если строки нет в таблице?
Метод вернёт -1. Это штатная ситуация, а не ошибка, поэтому результат всегда проверяют: если индекс меньше нуля, строка не принадлежит данной таблице значений, и дальнейшие вычисления номера проводить нельзя.
Как получить номера всех строк, удовлетворяющих условию?
Используйте НайтиСтроки() с структурой отбора — метод вернёт массив строк. Затем в цикле по массиву для каждой строки вызовите Индекс() и прибавьте единицу. На больших таблицах быстрее один обход всей таблицы со счётчиком и проверкой условия внутри цикла.
Сохранится ли номер строки после сортировки таблицы?
Нет. Индекс отражает текущую позицию, и после Сортировать(), Свернуть() или удаления строк он пересчитывается. Если номер должен переживать преобразования, добавьте числовую колонку и заполните её до любых операций с таблицей.
Чем отличается номер строки табличной части документа от индекса таблицы значений?
У строк табличной части есть автоматическое свойство НомерСтроки, начинающееся с единицы, — его поддерживает платформа. У таблицы значений такого свойства нет, есть только индекс с нуля. Если вы выгрузили табличную часть в таблицу значений через Выгрузить(), исходные номера сохранятся в одноимённой колонке, но обновлять их придётся вручную.
Как узнать номер текущей строки таблицы на управляемой форме?
Получите ТекущиеДанные элемента формы и передайте их в метод Индекс() реквизита-коллекции, прибавив единицу. Либо используйте свойство НомерСтроки текущих данных — но помните, что при включённом отборе в табличном поле отображаемый номер и индекс в коллекции могут различаться.
Что важно запомнить
Номер строки таблицы значений — это Индекс(Строка) + 1. Всегда проверяйте результат Найти() на Неопределено и результат Индекс() на -1. При обходе таблицы используйте счётчик в цикле, а если номер должен пережить сортировку или свёртку — храните его в отдельной колонке.