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

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

Как узнать индекс строки в 1С

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

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

Главная путаница у начинающих разработчиков — смешение индекса и номера строки. Номер строки в табличной части документа начинается с единицы и хранится в поле НомерСтроки, а индекс — это позиция в коллекции с нуля. Для первой строки индекс равен 0, а номер — 1. Это различие критично при программном обращении к строкам и при передаче данных между механизмами.

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

Чем индекс отличается от номера строки

Индекс — техническая позиция элемента в коллекции, отсчёт идёт с нуля. Номер строки — пользовательский реквизит табличной части, который видит пользователь в документе и который начинается с единицы. Если в табличной части три строки, их индексы — 0, 1, 2, а номера — 1, 2, 3.

Практическое следствие: формула связи выглядит как Индекс = НомерСтроки - 1. Это работает только пока строки не удаляли и коллекция не пересортировывалась программно без перенумерации. После сортировки таблицы значений номера строк могут не совпадать с реальными позициями, поэтому надёжнее вычислять индекс методом, а не арифметикой.

Как узнать индекс строки табличной части документа

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

Для Каждого СтрокаТовары Из Объект.Товары Цикл

ИндексСтроки = Объект.Товары.Индекс(СтрокаТовары);

// ИндексСтроки: 0, 1, 2...

КонецЦикла;

Частая задача — найти индекс строки по значению, например по номенклатуре. Для этого сначала ищут строки методом НайтиСтроки(), затем вычисляют индекс найденной строки:

Отбор = Новый Структура("Номенклатура", ИскомаяНоменклатура);

НайденныеСтроки = Объект.Товары.НайтиСтроки(Отбор);

Если НайденныеСтроки.Количество() > 0 Тогда

ИндексСтроки = Объект.Товары.Индекс(НайденныеСтроки[0]);

Иначе

// строка не найдена

КонецЕсли;

Если нужен именно номер, который видит пользователь, используйте свойство СтрокаТовары.НомерСтроки — для табличных частей оно заполняется автоматически. Не подменяйте индекс номером: при обращении Объект.Товары[НомерСтроки] вы получите не ту строку или ошибку выхода за границы коллекции.

Как узнать индекс строки таблицы значений

Таблица значений поддерживает тот же метод Индекс(). Логика идентична табличной части: передаёте строку — получаете позицию с нуля или -1.

ТЗ = Новый ТаблицаЗначений;

// ... заполнение таблицы

СтрокаТЗ = ТЗ.Найти(ИскомоеЗначение, "Артикул");

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

ИндексСтроки = ТЗ.Индекс(СтрокаТЗ);

КонецЕсли;

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

Индекс = 0;

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

// работа со строкой, позиция = Индекс

Индекс = Индекс + 1;

КонецЦикла;

Учтите: после вызова ТЗ.Сортировать() индексы строк меняются, а вот реквизит «НомерСтроки» у таблицы значений отсутствует — его при необходимости добавляют как обычную колонку и заполняют вручную. Если ваша логика завязана на стабильные номера, фиксируйте их до сортировки.

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

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

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

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

ИндексСтроки = Объект.Товары.ИндексСтроки(ТекущиеДанные);

КонецЕсли;

Ещё один путь — поле НомерСтроки текущих данных: Элементы.Товары.ТекущиеДанные.НомерСтроки. Это самый простой способ показать пользователю позицию строки, но помните про смещение на единицу при программном доступе по индексу.

Если нужно получить строку по известному индексу в форме, обращайтесь напрямую: Объект.Товары[ИндексСтроки]. Для проверки корректности перед обращением убедитесь, что индекс находится в диапазоне от 0 до Объект.Товары.Количество() - 1.

Порядок действий в форме
  1. 1
    Получите текущие данные: Элементы.Товары.ТекущиеДанные
  2. 2
    Проверьте, что они не Неопределено (строка выбрана)
  3. 3
    Вызовите Объект.Товары.ИндексСтроки(ТекущиеДанные)
  4. 4
    Проверьте результат: -1 означает, что строка не принадлежит коллекции
  5. 5
    Для показа пользователю прибавьте 1 или используйте НомерСтроки

Как получить номер (индекс) строки в запросе

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

РезультатЗапроса = Запрос.Выполнить().Выгрузить();

РезультатЗапроса.Колонки.Добавить("НомерСтроки");

Индекс = 1;

Для Каждого СтрокаТЗ Из РезультатЗапроса Цикл

СтрокаТЗ.НомерСтроки = Индекс;

Индекс = Индекс + 1;

КонецЦикла;

Второй подход — нумерация средствами запроса через самосоединение: для каждой строки подсчитывается количество строк с меньшим ключом упорядочивания. Такой приём работает, но на больших выборках заметно нагружает СУБД, поэтому для крупных таблиц предпочтительна программная нумерация после выгрузки.

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

Способы нумерации в запросе

Выгрузка и нумерация в цикле

Подходит почти всегда; ограничение — дополнительный проход по таблице в памяти

Самосоединение в запросе

Номер сразу в выборке; ограничение — медленно на больших объёмах

СКД НомерПоПорядку()

Удобно для отчётов; не работает вне механизма компоновки

Индекс строки в дереве значений и динамическом списке

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

В динамическом списке понятия стабильного индекса нет: состав и порядок строк зависят от отбора, сортировки и текущей выборки с сервера. Опираться на позицию строки в динамическом списке нельзя — идентифицируйте записи по ключу (ссылке), а не по индексу.

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

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

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

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

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

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

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

0 или больше, меньше Количество() коллекции

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

-1 (строка не найдена) или больше/равно Количество()

Обратное обращение Коллекция[Индекс]
Норма

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

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

Возвращается другая строка — смещение на единицу

Совпадение с НомерСтроки
Норма

Индекс = НомерСтроки - 1 для табличной части

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

Расхождение без видимой причины — коллекция пересортирована

Частые вопросы

Почему Индекс() возвращает -1?

Значение -1 означает, что переданная строка не принадлежит этой коллекции. Такое бывает, если строка получена из другой таблицы, из скопированной коллекции или была удалена. Проверяйте результат на -1 перед использованием индекса для доступа к элементам.

Как узнать индекс строки по значению в колонке?

Сначала найдите строку методом Найти() или НайтиСтроки(), затем передайте найденную строку в метод Индекс(). Напрямую по значению индекс получить нельзя — поиск и вычисление позиции выполняются в два шага.

Чем индекс отличается от НомерСтроки?

Индекс — позиция в коллекции с нуля, используется для программного доступа. НомерСтроки — реквизит табличной части с единицы, который видит пользователь. Связь: Индекс = НомерСтроки - 1, пока коллекция не пересортирована программно.

Как перебрать строки с индексами без метода Индекс()?

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

Можно ли получить индекс строки динамического списка?

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

Как пронумеровать строки результата запроса?

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

Итог

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

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