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

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

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

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

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

Главное, что нужно понимать сразу: индекс и номер строки — это разные вещи. Индекс начинается с нуля, а номер строки, который видит пользователь в колонке «№», начинается с единицы. Путаница между этими значениями — самая частая причина ошибок «Индекс находится за границами массива».

Ниже разобраны основные способы получения индекса: через метод Индекс(), через поиск по значениям, через перебор коллекции, а также особенности работы с управляемыми формами и объектами типа «ДанныеФормыКоллекция».

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

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

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

Практическое следствие: если вы хотите получить «человеческий» номер по индексу, прибавляйте единицу. Если по номеру строки нужно обратиться к элементу коллекции через Получить() или квадратные скобки — вычитайте единицу.

Метод Индекс() — основной способ

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

ТабЧасть = Объект.Товары;

ТекСтрока = ТабЧасть[0]; // первая строка

ИндексСтроки = ТабЧасть.Индекс(ТекСтрока); // вернёт 0

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

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

&НаКлиенте

Процедура ТоварыПриАктивизацииСтроки(Элемент)

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

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

Возврат;

КонецЕсли;

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

// Теперь можно обратиться к следующей строке

Если Индекс + 1 < Объект.Товары.Количество() Тогда

СледСтрока = Объект.Товары[Индекс + 1];

КонецЕсли;

КонецПроцедуры

Поиск индекса по значениям полей

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

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

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

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

Иначе

// строки с такой номенклатурой нет

КонецЕсли;

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

bsl
ПараметрыОтбора = Новый Структура("Номенклатура", НоменклатураСсылка);
НайденныеСтроки = Объект.Товары.НайтиСтроки(ПараметрыОтбора);
Для Каждого СтрокаТЧ Из НайденныеСтроки Цикл
    Индекс = Объект.Товары.Индекс(СтрокаТЧ);
КонецЦикла;

Получение индекса при переборе коллекции

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

// Вариант 1: цикл по индексам

Для Инд = 0 По Объект.Товары.Количество() - 1 Цикл

СтрокаТЧ = Объект.Товары[Инд];

// Инд — это и есть индекс строки

КонецЦикла;

// Вариант 2: счётчик в цикле "Для Каждого"

Инд = 0;

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

// Инд соответствует позиции СтрокаТЧ

Инд = Инд + 1;

КонецЦикла;

Первый вариант предпочтителен, когда внутри цикла нужен сам индекс или доступ к соседним строкам. Второй удобен, когда индекс нужен эпизодически. Помните: удалять строки внутри цикла «Для Каждого» нельзя — это приведёт к ошибке обхода коллекции.

Типичные ошибки
01
Обращение Товары[НомерСтроки] без вычитания единицы — выход за границы коллекции или обращение не к той строке
02
Удаление строк в прямом цикле обхода — коллекция сдвигается, часть строк пропускается; удаляйте в обратном порядке от конца к началу
03
Использование индекса, полученного до сортировки или удаления строк, — позиции уже изменились
04
Передача в Индекс() строки из другой табличной части — метод вернёт -1, что легко пропустить без проверки

Особенности управляемых форм

На управляемой форме табличная часть представлена объектом ДанныеФормыКоллекция. Метод Индекс() у неё есть и работает так же, но есть нюансы с получением текущей строки.

Свойство Элементы.Товары.ТекущаяСтрока возвращает не строку коллекции, а её идентификатор (число). Чтобы получить сами данные строки, используйте Объект.Товары.НайтиПоИдентификатору(ТекущаяСтрока) или свойство ТекущиеДанные элемента формы.

&НаКлиенте

Процедура ПоказатьИндекс(Команда)

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

Если ТекДанные = Неопределено Тогда

Возврат;

КонецЕсли;

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

Сообщить("Индекс: " + Индекс + ", номер строки: " + ТекДанные.НомерСтроки);

КонецПроцедуры

Обратное преобразование тоже возможно: по идентификатору строки можно получить индекс через Объект.Товары.Индекс(Объект.Товары.НайтиПоИдентификатору(Ид)). Это нужно, когда строка выбрана интерактивно, а дальше требуется работа с позицией.

Сравнение способов

Индекс() по известной строке

Быстрый и прямой способ, когда ссылка на строку уже есть. Ограничение: строка должна принадлежать именно этой коллекции

Найти() + Индекс()

Подходит, когда известны только значения реквизитов. Медленнее при большом объёме, находит первое совпадение

Цикл со счётчиком

Оптимален при массовой обработке, когда индекс нужен для каждой строки. Не подходит для поиска одной конкретной строки

НайтиПоИдентификатору()

Только для управляемых форм, когда есть идентификатор строки из элемента формы

Проверка результата и граничные случаи

После получения индекса всегда проверяйте его корректность перед использованием. Валидный индекс находится в диапазоне от 0 до Количество() - 1. Значение -1 означает, что строка в коллекции не найдена.

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

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

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

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

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

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

-1 или значение больше границы — строка не найдена или коллекция изменилась

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

НомерСтроки = Индекс + 1 при стандартной нумерации

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

Расхождение — нумерация сбита или строки перемещены

Обращение к соседней строке
Норма

Товары[Индекс+1] возвращает строку без ошибки

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

Ошибка «Индекс за границами» — проверку на Количество() не выполнили

Типовой порядок действий

Соберём всё в единую последовательность для самой распространённой задачи — найти строку и получить её индекс с защитой от ошибок.

Порядок действий
  1. 1
    Убедитесь, что табличная часть не пуста: проверьте Количество()
  2. 2
    Найдите строку методом Найти() или получите её из текущих данных формы
  3. 3
    Проверьте, что строка не равна Неопределено
  4. 4
    Получите индекс методом Индекс() коллекции
  5. 5
    Проверьте, что индекс не равен -1, прежде чем использовать его для обращения по позиции
  6. 6
    При обращении к соседним строкам дополнительно проверьте границы: Индекс+1 меньше Количества()

Такая последовательность исключает большинство ошибок времени выполнения и делает код устойчивым к изменениям данных пользователем.

Итог

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

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

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

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

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

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

Метод вернёт -1. Это происходит, если переданная строка принадлежит другой коллекции или уже удалена. Перед использованием индекса всегда проверяйте его на -1.

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

Возьмите Элементы.Товары.ТекущиеДанные — это объект данных строки, и передайте его в Объект.Товары.Индекс(). Свойство ТекущаяСтрока напрямую не подходит, так как содержит идентификатор, а не данные.

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

Напрямую в языке запросов функции индекса нет. Обычно выбирают НомерСтроки из табличной части и при необходимости вычитают единицу уже в коде, либо используют нумерацию через соединение таблицы с самой собой — но это оправдано редко.

Почему после удаления строки индексы «съехали»?

Коллекция автоматически сдвигается: все строки после удалённой получают индексы на единицу меньше. Поэтому при массовом удалении обходите коллекцию от конца к началу или работайте через список строк на удаление.

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

Индекс последней строки равен Объект.Товары.Количество() - 1. Если табличная часть пуста, результат будет -1, что корректно отражает отсутствие строк.