Как программно рассчитать и сформировать диапазон чисел с заданным шагом в 1С?

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

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

Базовая реализация алгоритма через цикл

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

Предположим, у нас есть реквизиты формы: НачальноеЧисло, КонечноеЧисло, Шаг и КоличествоЭлементов. Посмотрим на программный код процедуры, которая будет вызываться при нажатии кнопки «Выполнить»:


&НаКлиенте
Процедура ВыполнитьРасчет(Команда)
    
    // Очистим результат перед началом
    КоличествоЭлементов = 0;
    
    // Простейшая проверка входных данных
    Если НачальноеЧисло >= КонечноеЧисло Тогда
        Сообщить("Ошибка: Начальное число должно быть меньше конечного!");
        Возврат;
    КонецЕсли;
    
    Если Шаг <= 0 Тогда
        Сообщить("Ошибка: Шаг должен быть больше нуля!");
        Возврат;
    КонецЕсли;
    
    // Формируем массив
    РезультатМассив = ПолучитьДиапазон(НачальноеЧисло, КонечноеЧисло, Шаг);
    
    // Выводим количество полученных элементов
    КоличествоЭлементов = РезультатМассив.Количество();
    
    // Для наглядности можно вывести элементы в сообщение
    ТекстРезультата = СтрСоединить(РезультатМассив, ", ");
    Сообщить("Сформированный диапазон: " + ТекстРезультата);
    
КонецПроцедуры

&НаКлиенте
Функция ПолучитьДиапазон(Знач Старт, Знач Финиш, Знач ШагПриращения)
    
    ДиапазонЧисел = Новый Массив;
    ТекущееЧисло = Старт;
    
    Пока ТекущееЧисло <= Финиш Цикл
        ДиапазонЧисел.Добавить(ТекущееЧисло);
        ТекущееЧисло = ТекущееЧисло + ШагПриращения;
    КонецЦикла;
    
    Возврат ДиапазонЧисел;
    
КонецФункции

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

Типичные ошибки при работе с переменными

Разберем ситуацию, с которой часто сталкиваются новички. Иногда в коде можно встретить конструкции вида НачальноеЧисло = НачальноеЧисло;. Это происходит, когда разработчик пытается «переопределить» переменные внутри процедуры. С точки зрения компилятора 1С, такая строка не выполняет никаких действий. Если вы хотите скопировать значение реквизита формы в локальную переменную для расчетов, убедитесь, что имена различаются, либо используйте параметры процедур.

Также важно помнить о валидации данных. Проанализируем ситуацию: если пользователь введет шаг, равный нулю, программа войдет в «бесконечный цикл», так как условие ТекущееЧисло <= Финиш никогда не станет ложным. Поэтому проверка Если Шаг <= 0 является критически важной для стабильности системы.

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

Выясним, как сделать наш код более профессиональным. В 1С Массив является динамическим объектом. При каждом вызове метода Добавить() платформа может перераспределять память, что при очень больших диапазонах (например, миллионы записей) существенно замедляет работу. Рассмотрим, как оптимизировать этот процесс.

Мы можем заранее вычислить необходимое количество элементов по формуле:

Количество = Цел((КонечноеЧисло - НачальноеЧисло) / Шаг) + 1

Зная точное количество элементов, мы можем инициализировать массив сразу нужного размера. Посмотрим на оптимизированный фрагмент кода:


// Вычисляем количество заранее
КолВо = Цел((Финиш - Старт) / ШагПриращения) + 1;
ДиапазонЧисел = Новый Массив(КолВо);

Для Индекс = 0 По КолВо - 1 Цикл
    ДиапазонЧисел[Индекс] = Старт + (Индекс * ШагПриращения);
КонецЦикла;

Такой подход решает сразу две проблемы: во-первых, мы избегаем многократной очистки и выделения памяти. Во-вторых, расчет каждого элемента через умножение (Старт + Индекс * Шаг) помогает избежать накопления погрешности округления, которая часто возникает при работе с числами с плавающей точкой (тип Число с точностью более 0).

Работа с отрицательным шагом (Реверс)

Проанализируем ситуацию, когда нам нужно получить числа в порядке убывания (например, от 100 до 0 с шагом -10). Текущий алгоритм с условием ТекущееЧисло <= Финиш просто не сработает. Чтобы сделать функцию универсальной, добавим проверку направления движения:


// Универсальный обход
Если Старт < Финиш И ШагПриращения > 0 Тогда
    // Движение вверх
    Пока ТекущееЧисло <= Финиш Цикл
        ДиапазонЧисел.Добавить(ТекущееЧисло);
        ТекущееЧисло = ТекущееЧисло + ШагПриращения;
    КонецЦикла;
ИначеЕсли Старт > Финиш И ШагПриращения < 0 Тогда
    // Движение вниз
    Пока ТекущееЧисло >= Финиш Цикл
        ДиапазонЧисел.Добавить(ТекущееЧисло);
        ТекущееЧисло = ТекущееЧисло + ШагПриращения;
    КонецЦикла;
КонецЕсли;

Интерфейсные решения (UX)

Если предполагается, что расчет может занимать длительное время, пользователю необходимо предоставить обратную связь. Рассмотрим использование метода Состояние(). Он позволяет выводить текст в статус-строку в нижней части экрана, не прерывая выполнение кода модальными окнами.

Посмотрим, как можно интегрировать индикацию прогресса в наш цикл:


Для Индекс = 0 По КолВо - 1 Цикл
    // Каждые 1000 итераций обновляем статус
    Если Индекс % 1000 = 0 Тогда
        Процент = Цел(Индекс / КолВо * 100);
        Состояние("Выполняется расчет диапазона...", Процент);
    КонецЕсли;
    
    // Логика заполнения...
КонецЦикла;

Использование запросов для генерации последовательностей

В некоторых случаях, особенно когда результат нужно сразу соединить с данными из информационной базы (например, найти «дырки» в нумерации накладных за период), эффективнее использовать механизмы запросов. В 1С нет встроенной функции GENERATE_SERIES, как в PostgreSQL, но мы можем создать её аналог через соединение временных таблиц с цифрами от 0 до 9.

Разберем концепцию:

  1. Создаем временную таблицу Цифры с полями от 0 до 9.
  2. Соединяем её саму с собой несколько раз (декартово произведение), получая разряды: единицы, десятки, сотни.
  3. В поле выбора суммируем разряды, умноженные на их вес (1, 10, 100...).
  4. Накладываем фильтр ГДЕ, чтобы ограничить выборку нашим конечным числом.

Этот метод значительно быстрее работает на стороне СУБД, если вам требуется оперировать сотнями тысяч чисел в рамках одного отчета или сложного запроса.

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

← На главную