{}const=>[]async()letfn</>var
1CDesarrollo

Циклы в 1С: как обрабатывать списки, табличные части и выборки

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

К

Kodik

Autor

calendar_today
schedule6 min de lectura

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

Три кита: виды циклов в 1С

В платформе 1С:Предприятие существует три конструкции для организации циклов. Каждая заточена под свой сценарий.

Цикл «Для» — когда знаем количество итераций

Классический счётный цикл. Используется, когда заранее известно, сколько раз нужно выполнить действие.

Для Счетчик = 1 По 10 Цикл
    Сообщить("Итерация №" + Счетчик);
КонецЦикла;

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

Для Индекс = 0 По 9 Цикл
    РеальныйШаг = Индекс * 3;
    Сообщить("Значение: " + РеальныйШаг);
КонецЦикла;

Типичный сценарий — обход массива по индексу:

МассивТоваров = Новый Массив;
МассивТоваров.Добавить("Ноутбук");
МассивТоваров.Добавить("Монитор");
МассивТоваров.Добавить("Клавиатура");

Для Инд = 0 По МассивТоваров.ВГраница() Цикл
    Сообщить(МассивТоваров[Инд]);
КонецЦикла;

Цикл «Для Каждого» — универсальный солдат

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

Для Каждого Элемент Из МассивТоваров Цикл
    Сообщить(Элемент);
КонецЦикла;

Главное преимущество — вам не нужно думать об индексах, границах и количестве элементов. Вы просто работаете с каждым элементом коллекции.

Цикл «Пока» — когда условие выхода неизвестно заранее

Выполняется до тех пор, пока условие истинно. Идеален для ситуаций, когда количество итераций заранее неизвестно.

Остаток = 1000;
Месяц = 0;

Пока Остаток > 0 Цикл
    Остаток = Остаток - 150;
    Месяц = Месяц + 1;
КонецЦикла;

Сообщить("Средства закончатся через " + Месяц + " мес.");

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

Счетчик = 0;
Пока НеВыполненоУсловие И Счетчик < 10000 Цикл
    // логика обработки
    Счетчик = Счетчик + 1;
КонецЦикла;
🔥 100.000+ estudiantes ya están con nosotros

¿Cansado de leer teoría?
¡Hora de programar!

Kodik — una app donde aprendes a programar con práctica. Mentor IA, lecciones interactivas, proyectos reales.

🤖 IA 24/7
🎓 Certificados
💰 Gratis
🚀 Empezar
Se unieron hoy

Обработка табличных частей документов

Табличные части — одна из самых частых структур данных, с которой работает разработчик 1С. Разберём несколько практических задач.

Подсчёт суммы по табличной части

ИтогоСумма = 0;

Для Каждого СтрокаТЧ Из Документ.Товары Цикл
    ИтогоСумма = ИтогоСумма + СтрокаТЧ.Количество * СтрокаТЧ.Цена;
КонецЦикла;

Сообщить("Общая сумма: " + ИтогоСумма);

Удаление строк из табличной части

Вот тут начинается самое интересное. Классическая ошибка новичка — удалять строки в прямом цикле:

// ❌ ТАК ДЕЛАТЬ НЕЛЬЗЯ — пропустите строки!
Для Каждого СтрокаТЧ Из Документ.Товары Цикл
    Если СтрокаТЧ.Количество = 0 Тогда
        Документ.Товары.Удалить(СтрокаТЧ);
    КонецЕсли;
КонецЦикла;

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

// ✅ Корректный обратный обход
Инд = Документ.Товары.Количество() - 1;

Пока Инд >= 0 Цикл
    СтрокаТЧ = Документ.Товары[Инд];
    Если СтрокаТЧ.Количество = 0 Тогда
        Документ.Товары.Удалить(Инд);
    КонецЕсли;
    Инд = Инд - 1;
КонецЦикла;

Поиск дубликатов в табличной части

Задача, которая встречается постоянно: найти и объединить одинаковые товары.

Инд = 0;
Пока Инд < Документ.Товары.Количество() Цикл
    ТекСтрока = Документ.Товары[Инд];
    
    Инд2 = Инд + 1;
    Пока Инд2 < Документ.Товары.Количество() Цикл
        СравнСтрока = Документ.Товары[Инд2];
        
        Если ТекСтрока.Номенклатура = СравнСтрока.Номенклатура Тогда
            ТекСтрока.Количество = ТекСтрока.Количество + СравнСтрока.Количество;
            Документ.Товары.Удалить(Инд2);
        Иначе
            Инд2 = Инд2 + 1;
        КонецЕсли;
    КонецЦикла;
    
    Инд = Инд + 1;
КонецЦикла;

Обратите внимание: при удалении дубликата мы не увеличиваем Инд2, потому что на его место сдвинется следующий элемент.

Работа с выборками из запросов

Результат запроса в 1С — это не массив, а специальный объект, который обходится особым образом.

Базовый обход выборки

Запрос = Новый Запрос;
Запрос.Текст = 
    "ВЫБРАТЬ
    |    Номенклатура.Наименование КАК Наименование,
    |    Номенклатура.Цена КАК Цена
    |ИЗ
    |    Справочник.Номенклатура КАК Номенклатура
    |ГДЕ
    |    Номенклатура.Цена > 0";

Результат = Запрос.Выполнить();
Выборка = Результат.Выбрать();

Пока Выборка.Следующий() Цикл
    Сообщить(Выборка.Наименование + ": " + Выборка.Цена + " руб.");
КонецЦикла;

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

Обход иерархической выборки

Для справочников с иерархией удобно использовать выборку с группировками:

Результат = Запрос.Выполнить();
ВыборкаГруппы = Результат.Выбрать(ОбходРезультатаЗапроса.ПоГруппировкам);

Пока ВыборкаГруппы.Следующий() Цикл
    Сообщить("== Группа: " + ВыборкаГруппы.Категория + " ==");
    
    ВыборкаДетали = ВыборкаГруппы.Выбрать();
    Пока ВыборкаДетали.Следующий() Цикл
        Сообщить("   " + ВыборкаДетали.Наименование);
    КонецЦикла;
КонецЦикла;

Пакетные запросы с несколькими результатами

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

МассивРезультатов = Запрос.ВыполнитьПакет();

Для Каждого РезультатЗапроса Из МассивРезультатов Цикл
    Выборка = РезультатЗапроса.Выбрать();
    Пока Выборка.Следующий() Цикл
        // обработка строки
    КонецЦикла;
КонецЦикла;

Обход структур и соответствий

Структуры и соответствия — это пары «ключ-значение». Их обходят через Для Каждого:

Параметры = Новый Структура;
Параметры.Вставить("Организация", "ООО Ромашка");
Параметры.Вставить("Период", ТекущаяДата());
Параметры.Вставить("Склад", "Основной");

Для Каждого КлючЗначение Из Параметры Цикл
    Сообщить(КлючЗначение.Ключ + " = " + КлючЗначение.Значение);
КонецЦикла;

Для соответствий синтаксис аналогичен, но соответствие допускает ключи любого типа — не только строки.

Управление циклом: Прервать и Продолжить

Два оператора позволяют гибко управлять ходом цикла.

Прервать — немедленно выходит из цикла:

Для Каждого Товар Из Каталог Цикл
    Если Товар.Наименование = "Искомый товар" Тогда
        НайденныйТовар = Товар;
        Прервать;
    КонецЕсли;
КонецЦикла;

Продолжить — пропускает оставшийся код итерации и переходит к следующей:

Для Каждого Контрагент Из СписокКонтрагентов Цикл
    Если Контрагент.ЭтоГруппа Тогда
        Продолжить; // группы пропускаем
    КонецЕсли;
    
    // обработка только элементов
    ОбработатьКонтрагента(Контрагент);
КонецЦикла;

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

Есть несколько правил, которые помогут писать быстрые и надёжные циклы в 1С.

Не обращайтесь к базе внутри цикла. Каждый вызов к базе данных — это сетевой запрос. Если у вас 10 000 строк, вы сделаете 10 000 обращений к серверу. Вместо этого получите все нужные данные одним запросом до цикла:

// ❌ Медленно: запрос внутри цикла
Для Каждого СтрокаТЧ Из Документ.Товары Цикл
    Остаток = РегистрыНакопления.ОстаткиТоваров
        .ПолучитьПоследнийСрез(, "Номенклатура = &Ном");
КонецЦикла;

// ✅ Быстро: один запрос, потом цикл
Запрос = Новый Запрос;
Запрос.Текст = "ВЫБРАТЬ Номенклатура, Остаток ИЗ ...";
ТаблицаОстатков = Запрос.Выполнить().Выгрузить();

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

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

// ❌ Вложенный цикл O(n²)
Для Каждого Строка1 Из Таблица1 Цикл
    Для Каждого Строка2 Из Таблица2 Цикл
        Если Строка1.Ключ = Строка2.Ключ Тогда
            // ...
        КонецЕсли;
    КонецЦикла;
КонецЦикла;

// ✅ Поиск через НайтиСтроки O(n)
Для Каждого Строка1 Из Таблица1 Цикл
    Отбор = Новый Структура("Ключ", Строка1.Ключ);
    НайденныеСтроки = Таблица2.НайтиСтроки(Отбор);
    Для Каждого НайдСтрока Из НайденныеСтроки Цикл
        // ...
    КонецЦикла;
КонецЦикла;

Для больших объёмов данных используйте индексирование через Соответствие:

Индекс = Новый Соответствие;
Для Каждого Строка Из Таблица2 Цикл
    Индекс.Вставить(Строка.Ключ, Строка);
КонецЦикла;

Для Каждого Строка1 Из Таблица1 Цикл
    НайденнаяСтрока = Индекс.Получить(Строка1.Ключ);
    Если НайденнаяСтрока <> Неопределено Тогда
        // работаем с найденной строкой
    КонецЕсли;
КонецЦикла;

Этот приём превращает O(n²) во O(n) и критически важен при обработке тысяч строк.

Шпаргалка: какой цикл выбрать?

Задача

Цикл

Почему

Обход массива с индексом

Для … По

Нужен доступ по индексу

Обход табличной части

Для Каждого

Самый читаемый вариант

Удаление строк из коллекции

Пока (обратный обход)

Избегаем пропуска элементов

Выборка результата запроса

Пока Выборка.Следующий()

Единственный способ обхода

Повторение до условия

Пока

Количество итераций неизвестно

Обход структуры/соответствия

Для Каждого

Получаем пары ключ-значение

Заключение

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

Если вы только начинаете путь в программировании или хотите освоить новые технологии — загляните в приложение Кодик. Там вы найдёте структурированные курсы по Python, JavaScript, HTML, CSS и другим языкам, которые помогут разобраться в основах и перейти к реальным задачам. А в нашем Telegram-канале всегда можно задать вопрос, получить поддержку от сообщества из более чем 2000 разработчиков и быть в курсе новых материалов. Программирование — это проще, чем кажется, когда рядом есть те, кто готов помочь.

🎯Deja de postergar

¿Te gustó el artículo?
¡Hora de practicar!

En Kodik no solo lees — escribes código de inmediato. Teoría + práctica = habilidades reales.

Práctica instantánea
🧠IA explica código
🏆Certificado

Sin registro • Sin tarjeta