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