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

Программист 1С v8.3 (Обычные формы) IT и автоматизация бизнеса
← На главную

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

Разбор типичной ошибки при обращении к данным

Проанализируем ситуацию, с которой часто сталкиваются разработчики при попытке организовать двойной цикл (по строкам и по колонкам). Рассмотрим ошибочный фрагмент кода, который приводит к исключению "Получение элемента по индексу для значения не определено":


Для каждого СтрТч Из ТаблицаЗагрузки Цикл
    Для каждого СтрКолонка Из ТаблицаЗагрузки.Колонки Цикл 
        // ОШИБКА: ТаблицаЗагрузки[СтрТч][СтрКолонка.Имя]
        Сообщить(ТаблицаЗагрузки[СтрТч][СтрКолонка.Имя]); 
    КонецЦикла;
КонецЦикла;

Выясним причину этой ошибки. В платформе 1С метод Для каждого ... Из ... при обходе объекта ТаблицаЗначений возвращает в переменную цикла (в нашем примере СтрТч) объект типа СтрокаТаблицыЗначений. Пытаясь написать ТаблицаЗагрузки[СтрТч], программист пытается использовать объект строки в качестве индекса для самой таблицы. Это неверно, так как таблица ожидает в квадратных скобках либо числовой индекс (0, 1, 2...), либо саму строку, но только если это предусмотрено логикой поиска. Однако двойная вложенность (индекс от индекса) здесь излишня.

Правильный алгоритм универсального перебора

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


// Универсальный обход таблицы значений
Для Каждого СтрокаТЗ Из ТаблицаЗагрузки Цикл
    // Внутренний цикл по коллекции колонок позволяет сделать код независимым от структуры
    Для Каждого ТекущаяКолонка Из ТаблицаЗагрузки.Колонки Цикл
        
        // Получаем имя колонки динамически
        ИмяКолонки = ТекущаяКолонка.Имя;
        
        // Обращаемся к значению в данной строке по имени колонки
        Значение = СтрокаТЗ[ИмяКолонки];
        
        // Теперь мы можем обрабатывать значение
        Сообщить("В колонке " + ИмяКолонки + " содержится значение: " + Значение);
        
    КонецЦикла;
КонецЦикла;

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

Оптимизация работы с колонками через индексы

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


// Определяем индексы нужных колонок заранее
ИндексНоменклатуры = ТаблицаЗагрузки.Колонки.Индекс(ТаблицаЗагрузки.Колонки.Номенклатура);
ИндексКоличества = ТаблицаЗагрузки.Колонки.Индекс(ТаблицаЗагрузки.Колонки.Количество);

Для Каждого Стр Из ТаблицаЗагрузки Цикл
    // Обращение по индексу работает быстрее в больших циклах
    ТекНоменклатура = Стр.Получить(ИндексНоменклатуры);
    ТекКоличество = Стр.Получить(ИндексКоличества);
    
    // Выполняем полезную работу
КонецЦикла;

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

Безопасный доступ и проверка существования колонок

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


ИмяНужнойКолонки = "Склад";
КолонкаОбъект = ТаблицаЗагрузки.Колонки.Найти(ИмяНужнойКолонки);

Если КолонкаОбъект <> Неопределено Тогда
    // Колонка существует, можно безопасно перебирать таблицу
    Для Каждого Стр Из ТаблицаЗагрузки Цикл
        ЗначениеСклада = Стр[ИмяНужнойКолонки];
    КонецЦикла;
Иначе
    Сообщить("В таблице отсутствует колонка " + ИмяНужнойКолонки);
КонецЕсли;

Метод Найти() коллекции колонок возвращает объект колонки или Неопределено, если такая колонка не найдена. Это правило хорошего тона при разработке внешних обработок заполнения или загрузки данных.

Использование встроенных методов вместо ручного перебора

Иногда перебор строк вовсе не требуется, если задача состоит в простом манипулировании данными. Рассмотрим альтернативные методы объекта ТаблицаЗначений:

  1. Заполнение всей колонки одним значением: Вместо цикла Для каждого используем ТаблицаЗагрузки.ЗаполнитьЗначения(ТекущаяДата(), "ДатаОбработки");. Это работает мгновенно на любом объеме данных.
  2. Выгрузка данных в массив: Если нужно получить список всех уникальных значений колонки, используем МассивЗначений = ТаблицаЗагрузки.ВыгрузитьКолонку("Контрагент");. Далее с массивом работать проще и быстрее.
  3. Поиск конкретных строк: Метод НайтиСтроки() позволяет получить массив строк, соответствующих структуре отбора, без полного сканирования таблицы вручную.

Особенности производительности в обычном приложении

Проанализируем аспект визуализации. В обычном приложении таблица значений на форме часто связана с элементом управления "Табличное поле". Если ваш цикл перебора подразумевает изменение данных (например, перезаполнение цен), каждое изменение строки может вызывать перерисовку интерфейса, что существенно замедляет выполнение кода.

Чтобы ускорить процесс, рекомендуем придерживаться следующих правил:

1. Если таблица большая, перед началом цикла отключите обновление формы или работайте с копией таблицы в памяти (через метод Скопировать()).

2. Используйте методы массового изменения (ЗаполнитьЗначения), если это возможно.

3. При переборе старайтесь минимизировать количество обращений к свойствам через точку (выносите их в переменные внутри цикла).

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

← На главную