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

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

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

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

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

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

Материал ориентирован на платформу 1С:Предприятие 8.3 и подходит как для управляемых, так и для обычных форм. Синтаксис одинаков, различия касаются только контекста выполнения (клиент или сервер) и доступности некоторых методов.

Базовый перебор циклом «Для Каждого»

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

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

СуммаСтроки = СтрокаТЗ.Количество * СтрокаТЗ.Цена;

СтрокаТЗ.Сумма = СуммаСтроки;

КонецЦикла;

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

Если значение колонки нужно получить по имени, хранящемуся в переменной, используйте квадратные скобки: СтрокаТЗ[ИмяКолонки]. Это типичный приём в универсальных обработках, где структура таблицы заранее неизвестна.

Перед обращением к колонке убедитесь, что она существует, особенно если таблица формируется динамически: Если ТаблицаТоваров.Колонки.Найти("Сумма") <> Неопределено Тогда ... КонецЕсли;. Обращение к несуществующей колонке вызывает ошибку времени выполнения.

Перебор по индексу: когда нужен номер строки

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

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

СтрокаТЗ = ТаблицаТоваров[Сч];

// СтрокаТЗ — текущая строка, Сч — её индекс

КонецЦикла;

Индексация строк в таблице значений начинается с нуля, поэтому верхняя граница цикла — Количество() - 1. Распространённая ошибка — писать цикл от 1 до Количество(): первая строка пропускается, а на последней итерации возникает обращение за границу массива.

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

Удаление строк во время перебора

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

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

Индекс = -Сч;

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

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

КонецЕсли;

КонецЦикла;

Альтернатива — собрать строки к удалению в отдельный массив во время прямого перебора, а затем удалить их вторым проходом. Этот вариант нагляднее и удобнее, когда условие удаления сложное.

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

Типичные ошибки
01
Удаление строк внутри цикла «Для Каждого» — коллекция смещается, часть строк пропускается или возникает ошибка.
02
Цикл от 1 до Количество() — пропуск первой строки и выход за границу на последней итерации.
03
Сравнение значений разных типов без приведения — строка «10» не равна числу 10, условие молча не срабатывает.
04
Обращение к колонке без проверки её существования — ошибка времени выполнения на таблицах с динамической структурой.

Поиск строк по условию: НайтиСтроки и Найти

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

Отбор = Новый Структура;

Отбор.Вставить("Склад", СкладОтгрузки);

Отбор.Вставить("Отгружено", Ложь);

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

Для Каждого СтрокаТЗ Из НайденныеСтроки Цикл

СтрокаТЗ.Отгружено = Истина;

КонецЦикла;

Если достаточно одной строки, используйте метод Найти(Значение, ИмяКолонки) — он возвращает первую найденную строку или Неопределено. Всегда проверяйте результат на Неопределено перед обращением к колонкам, иначе получите ошибку «Поле объекта не обнаружено».

Ограничение обоих методов — отбор только на равенство. Условия вида «больше», «содержит подстроку» или «дата в диапазоне» через НайтиСтроки не выразить: придётся либо перебирать вручную, либо переносить логику в запрос, где доступен полноценный ГДЕ.

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

Для Каждого

Универсальный полный обход. Не даёт индекс строки и не позволяет удалять строки внутри цикла.

Цикл по индексу

Нужен, когда важен номер строки или идёт удаление. Чуть более громоздкий код.

НайтиСтроки()

Отбор по равенству одного или нескольких полей. Быстро и кратко, но без сложных условий.

Запрос к таблице

Сложные условия, группировки, соединения. Требует поместить таблицу во временную таблицу — оправдано на больших объёмах.

Выгрузка колонки и свёртка таблицы

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

Обратная задача — собрать из массива колонку — решается методом ЗагрузитьКолонку(Массив, "ИмяКолонки"). Оба метода заметно короче ручных циклов и меньше подвержены ошибкам.

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

Производительность и работа с большими таблицами

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

Для поиска по таблице внутри цикла используйте НайтиСтроки с предварительно построенным индексом: метод ТаблицаТоваров.Индексы.Добавить("Номенклатура") ускоряет повторные поиски по этой колонке. Без индекса каждый вызов НайтиСтроки сканирует таблицу целиком.

Помните и о контексте выполнения. Перебор большой таблицы на клиенте в управляемом приложении при передаче данных с сервера может давать множество серверных вызовов. Обработку объёмных данных размещайте в серверных процедурах с директивой &НаСервере или &НаСервереБезКонтекста.

Проверка результата после перебора

После обработки таблицы полезно убедиться, что результат соответствует ожиданиям. Минимальный набор проверок: количество строк до и после, итоги по суммовым колонкам (ТаблицаТоваров.Итог("Сумма")) и отсутствие строк с незаполненными обязательными полями.

Для отладки удобно выводить промежуточные данные через Сообщить() или смотреть таблицу в отладчике через «Вычислить выражение» — таблица значений отображается в виде привычной сетки. В толстом клиенте доступна команда «Показать значение в отдельном окне».

Если перебор входит в состав длительной операции, добавьте индикацию прогресса через ДлительныеОперации или хотя бы запись в журнал регистрации — это упростит поиск причины, если обработка завершится с ошибкой посередине.

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

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

Количество строк после обработки
Норма

Совпадает с ожидаемым числом (или уменьшилось ровно на число удалённых)

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

Строк пропало или добавилось больше, чем предполагала логика

Итоги по суммовым колонкам
Норма

Итог(«Сумма») соответствует контрольному значению

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

Итог расходится — часть строк не обработана или обработана дважды

Незаполненные поля
Норма

Обязательные колонки заполнены во всех строках

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

Есть пустые значения — условие в цикле сработало не для всех строк

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

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

Используйте метод Количество(): ТаблицаТоваров.Количество(). Для проверки на пустоту достаточно сравнения с нулём. Отдельного метода «Пустая» у таблицы значений нет.

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

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

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

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

Как перебрать таблицу в обратном порядке?

Только циклом по индексу с шагом -1: Для Сч = -Таблица.Количество() + 1 По 0 Цикл с вычислением индекса как -Сч. Цикл «Для Каждого» всегда идёт от первой строки к последней.

Почему НайтиСтроки возвращает пустой массив, хотя значение в таблице есть?

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

Что быстрее: перебор таблицы значений или запрос?

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

Итог

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

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