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