При разработке алгоритмов часто возникает задача классификации числовых данных по определенным интервалам. Типичный пример — группировка чисел по десяткам: число 12 должно попасть в категорию «от 10 до 19», 25 — в «от 20 до 29», и так далее. Если диапазон чисел невелик, можно обойтись простыми условиями, но когда числа достигают 999 и более, написание сотен конструкций Если...ИначеЕсли становится нерациональным. В этой статье мы разберем несколько профессиональных способов решения этой задачи, начиная от простой математики и заканчивая сложными аналитическими инструментами.
Рассмотрим самый быстрый и элегантный способ, основанный на базовой арифметике. Чтобы понять, к какому десятку относится число, нам достаточно разделить его на 10 и отбросить дробную часть. В языке 1С для этого используется функция Цел().
Проанализируем ситуацию: если мы разделим 12 на 10, получим 1.2. Функция Цел(1.2) вернет нам 1. Умножив этот результат обратно на 10, мы получим нижнюю границу диапазона. Разберем этот алгоритм по шагам в коде:
// Предположим, наше число находится в переменной ТестовоеЧисло
ТестовоеЧисло = 125;
// Определяем номер группы (сколько полных десятков в числе)
НомерГруппы = Цел(ТестовоеЧисло / 10);
// Вычисляем границы диапазона
НижняяГраница = НомерГруппы * 10;
ВерхняяГраница = НижняяГраница + 9;
// Формируем строковое представление
Результат = "от " + Строка(НижняяГраница) + " до " + Строка(ВерхняяГраница);
Этот метод является наиболее производительным, так как он не требует перебора коллекций или выполнения сложных логических проверок. Он работает мгновенно для любого числа в пределах допустимых значений типа Число.
Выяснив математическую логику, мы можем улучшить читаемость кода и удобство формирования вывода. В современных версиях платформы 1С:Предприятие 8.3 для сборки строк рекомендуется использовать функцию СтрШаблон(). Это делает код более «чистым» и упрощает его поддержку.
Посмотрим на пример реализации функции, которая возвращает текстовое описание диапазона:
Функция ПолучитьТекстДиапазона(Знач Число) Экспорт
НомерГруппы = Цел(Число / 10);
Начало = НомерГруппы * 10;
Конец = Начало + 9;
Возврат СтрШаблон("от %1 до %2", Формат(Начало, "ЧГ=0"), Формат(Конец, "ЧГ=0"));
КонецФункции
Обратите внимание на использование функции Формат с параметром ЧГ=0. Это гарантирует, что в больших числах (например, 1000) не появятся разделители групп разрядов (неразрывные пробелы), которые могут испортить строковый результат.
Иногда задача стоит сложнее: нам нужно не просто вычислить диапазон, а сопоставить его с каким-то уникальным именем или объектом. В этом случае удобно использовать объект Соответствие. Рассмотрим ситуацию, когда для определенных десятков у нас есть специфические названия.
Диапазоны = Новый Соответствие;
Диапазоны.Вставить(1, "Первый десяток (10-19)");
Диапазоны.Вставить(2, "Второй десяток (20-29)");
// ... и так далее
НомерГруппы = Цел(ПроверяемоеЧисло / 10);
НаименованиеГруппы = Диапазоны.Получить(НомерГруппы);
Если НаименованиеГруппы = Неопределено Тогда
НаименованиеГруппы = "Группа не определена";
КонецЕсли;
Важный момент: если групп очень много (как в нашем случае до 999), заполнять Соответствие вручную — плохая идея. Коллекции лучше использовать тогда, когда интервалы имеют произвольную длину или специфические атрибуты.
Если в будущем условия задачи изменятся и группы станут неравномерными (например: 10–19, но затем 20–49, а потом 50–99), математическая формула перестанет работать. В таких случаях мы рекомендуем использовать ТаблицаЗначений и цикл.
Разберем, как реализовать универсальный поиск диапазона:
// Создаем таблицу границ
ТаблицаГраниц = Новый ТаблицаЗначений;
ТаблицаГраниц.Колонки.Добавить("НижняяГрань", Новый ОписаниеТипов("Число"));
ТаблицаГраниц.Колонки.Добавить("Представление", Новый ОписаниеТипов("Строка"));
// Заполняем данными (можно из справочника или программно)
НоваяСтрока = ТаблицаГраниц.Добавить();
НоваяСтрока.НижняяГрань = 10;
НоваяСтрока.Представление = "От 10 до 19";
// Поиск нужного диапазона
ИскомыйДиапазон = "Не найден";
// Сортируем по убыванию для корректного поиска первого вхождения "снизу"
ТаблицаГраниц.Сортировать("НижняяГрань Убыв");
Для Каждого Стр Из ТаблицаГраниц Цикл
Если ПроверяемоеЧисло >= Стр.НижняяГрань Тогда
ИскомыйДиапазон = Стр.Представление;
Прервать; // Нашли ближайшую нижнюю границу
КонецЕсли;
КонецЦикла;
Зачастую группировка чисел требуется при формировании отчетов. Выполнять такие вычисления в цикле после выборки данных — неоптимально. Правильнее переложить эту задачу на СУБД, используя язык запросов.
Поскольку в языке запросов нет прямой функции Цел(), мы воспользуемся функцией ВЫРАЗИТЬ. Однако стоит помнить, что ВЫРАЗИТЬ(Число КАК ЧИСЛО(10, 0)) выполняет математическое округление к ближайшему целому, а не простое отсечение. Чтобы реализовать логику «десяток вниз», проанализируем следующую конструкцию:
ВЫБРАТЬ
Продажи.Сумма КАК Сумма,
ВЫРАЗИТЬ((Продажи.Сумма - 5) / 10 КАК ЧИСЛО(10, 0)) * 10 КАК НачалоДиапазона
ИЗ
РегистрНакопления.Продажи КАК Продажи
ГДЕ
Продажи.Сумма >= 10
Вычитая 5 перед делением и округлением, мы заставляем систему округлять число так, чтобы результат соответствовал началу текущего десятка. Это мощный инструмент для построения гистограмм и аналитических отчетов прямо в запросе.
Если вы разрабатываете отчет на СКД, можно пойти еще дальше и создать Вычисляемое поле. В выражении вычисляемого поля можно использовать функции общего модуля. Это позволит пользователю группировать данные по диапазонам так же легко, как по контрагентам или номенклатуре.
Рассмотрим преимущества этого подхода:
НСтр() внутри вашего общего модуля, чтобы заголовки групп («от... до...») автоматически переводились на язык пользователя в мультиязычных конфигурациях.Подведем итог нашему анализу. Выбор метода зависит от контекста вашей задачи:
Помните, что отказ от сотен условий Если...ИначеЕсли не только экономит время программиста, но и делает программу значительно более устойчивой к ошибкам и легкой в сопровождении. Мы рассмотрели основные подходы, которые помогут вам писать качественный и профессиональный код в среде 1С.