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

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

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

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

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

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

Важно понимать разницу между индексом строки и её содержимым. Индекс — это позиция в коллекции, он меняется при удалении и вставке строк. Если вы сохранили индекс, а затем удалили строку выше, все последующие индексы «съедут» на единицу. Это одна из самых частых причин ошибок при работе с таблицами значений.

Метод Индекс() — прямой способ получить позицию строки

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

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

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

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

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

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

Сообщить("Индекс строки: " + ПозицияСтроки);

КонецЕсли;

Метод возвращает число от 0 до Количество() - 1. Если переданная строка не принадлежит этой таблице значений, метод вернёт -1. Это удобно для проверки принадлежности строки конкретной коллекции.

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

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

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

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

ТекущаяСтрока = ТаблицаТоваров[ИндексСтроки];

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

КонецЦикла;

Обращение к строке по индексу выполняется через квадратные скобки: ТаблицаТоваров[ИндексСтроки]. Это быстрый способ доступа, он не выполняет поиск по значениям — платформа сразу возвращает строку по позиции.

Индекс в цикле «Для Каждого»

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

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

Позиция = ТаблицаТоваров.Индекс(СтрокаТовара);

// работа со строкой и её позицией

КонецЦикла;

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

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

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

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

Для Каждого + Индекс()

Удобно, если индекс нужен изредка. На больших таблицах медленнее из-за повторного поиска строки.

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

Оптимально, когда нужна позиция одной конкретной строки по значению колонки.

Поиск строки по значению и получение её индекса

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

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

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

Сообщить("Строка не найдена");

Иначе

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

КонецЕсли;

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

Несколько совпадений: метод НайтиСтроки()

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

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

МассивСтрок = ТаблицаТоваров.НайтиСтроки(Отбор);

Для Каждого Строка Из МассивСтрок Цикл

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

КонецЦикла;

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

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

Индекс текущей строки табличного поля на форме

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

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

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

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

Позиция = Товары.Индекс(ТекущаяСтрокаДанные);

Сообщить("Выделена строка с индексом " + Позиция);

КонецЕсли;

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

Удаление и вставка строк по индексу: подводные камни

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

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

// Вариант 1: обратный перебор

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

ИндексСтроки = ТаблицаТоваров.Количество() - Счетчик;

Если ТаблицаТоваров[ИндексСтроки].Количество = 0 Тогда

ТаблицаТоваров.Удалить(ИндексСтроки);

КонецЕсли;

КонецЦикла;

// Вариант 2: через массив строк

СтрокиКУдалению = ТаблицаТоваров.НайтиСтроки(Новый Структура("Количество", 0));

Для Каждого Строка Из СтрокиКУдалению Цикл

ТаблицаТоваров.Удалить(Строка);

КонецЦикла;

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

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

Проверка корректности полученного индекса

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

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

Если Позиция >= 0 И Позиция < ТаблицаТоваров.Количество() Тогда

// индекс валиден, можно обращаться к строке

Строка = ТаблицаТоваров[Позиция];

КонецЕсли;

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

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

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

Значение, возвращённое методом Индекс()
Норма

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

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

-1 (строка не из этой таблицы) или выход за границы

Обращение ТЗ[Индекс] после поиска
Норма

Возвращается именно та строка, которую искали

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

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

Поведение цикла с удалением
Норма

Обработаны все строки, лишних пропусков нет

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

Часть строк пропущена — признак сдвига индексов при удалении

Частые вопросы об индексах строк таблицы значений

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

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

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

Да: сначала вызовите ТЗ.Найти(Значение, "ИмяКолонки"), затем примените ТЗ.Индекс() к найденной строке. Прямого метода «индекс по значению» в платформе нет, но эта связка выполняется быстро и не требует ручного перебора.

Почему Индекс() возвращает -1, хотя строка точно есть в таблице?

Чаще всего строка получена из другой таблицы значений — например, из копии, созданной методом Скопировать(). Строки копии и оригинала — разные объекты. Проверьте, что ищете позицию именно в той таблице, из которой получена строка.

Меняется ли индекс строки после сортировки таблицы?

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

Что быстрее на большой таблице: Индекс() или перебор?

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

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

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

Итог

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

Индекс строки таблицы значений получают методом ТЗ.Индекс(Строка) или счётчиком в цикле Для от 0 до Количество()-1. Перед использованием проверяйте результат Найти() на Неопределено, помните о нумерации с нуля и о сдвиге индексов при удалении и сортировке строк. Для удаления безопаснее передавать в Удалить() саму строку, а не её индекс.