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

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

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

Способ 1: Использование функции Вычислить() и агрегата Макс()

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

Разберем этот метод по шагам:

  1. Сначала нам нужно избавиться от всех символов, которые не являются цифрами. Для этого мы можем использовать комбинацию СтрРазделить и СтрСоединить.
  2. Получив массив «чистых» строк, мы снова соединяем их, но уже через запятую.
  3. Формируем строку вида "Макс(Число1, Число2, ...)" и передаем её в функцию Вычислить().

Посмотрим на пример реализации:


ВходнаяСтрока = "09ы!!выв0000032323ав??@а678900ллл1212";
// Получаем все не-цифровые последовательности как разделители
Разделители = СтрСоединить(СтрРазделить(ВходнаяСтрока, "0123456789", Ложь), "");
// Разбиваем строку по найденным разделителям, получая только числа
Коллекция = СтрРазделить(ВходнаяСтрока, Разделители, Ложь);
// Формируем код для исполнения
СтрокаКода = "Макс(" + СтрСоединить(Коллекция, ",") + ")";
Максимум = Вычислить(СтрокаКода);
Сообщить("Максимальное число: " + Максимум);

Важное ограничение: У функции Макс() во встроенном языке есть лимит на количество передаваемых параметров. Если чисел в строке будет очень много (несколько тысяч), этот метод вызовет ошибку переполнения стека или ограничения количества аргументов.

Способ 2: Рекурсивный обход данных

Если циклы запрещены, классической заменой им выступает рекурсия. Мы можем создать процедуру, которая вызывает сама себя, пока не обработает все элементы коллекции. Выясним причину, почему этот способ часто используется на собеседованиях: он показывает умение работать со стеком вызовов.

Рассмотрим вариант с заполнением ТаблицыЗначений для последующей сортировки:


Процедура НайтиМаксимумРекурсивно(ВходящаяСтрока)
    // Извлекаем числа (упрощенно через фиксированный набор разделителей)
    МассивЧисел = СтрРазделить(ВходящаяСтрока, " ,!@#%^&*()", Ложь);
    
    ТаблицаЧисел = Новый ТаблицаЗначений;
    // Явно задаем тип Число, чтобы избежать строковой сортировки
    ТаблицаЧисел.Колонки.Добавить("Число", Новый ОписаниеТипов("Число"));
    
    ДобавитьСтрокуРекурсивно(ТаблицаЧисел, МассивЧисел, МассивЧисел.Количество());
    
    ТаблицаЧисел.Сортировать("Число УБЫВ");
    МаксимальноеЧисло = ТаблицаЧисел[0].Число;
    Сообщить(МаксимальноеЧисло);
КонецПроцедуры

Процедура ДобавитьСтрокуРекурсивно(Таблица, Массив, Осталось)
    Если Осталось = 0 Тогда Возврат; КонецЕсли;
    
    НоваяСтрока = Таблица.Добавить();
    НоваяСтрока.Число = Число(Массив[Осталось - 1]);
    
    ДобавитьСтрокуРекурсивно(Таблица, Массив, Осталось - 1);
КонецПроцедуры

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

Способ 3: Использование типизированного СпискаЗначений

Посмотрим на более простой вариант с использованием объекта СписокЗначений. Ошибка многих разработчиков заключается в том, что они просто загружают массив строк в список и сортируют его. Но строки "9" и "10" сортируются так, что "9" оказывается больше "10" (лексикографический порядок).

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

Способ 4: Проверка на делимость на 17 (дополнительная задача)

Часто в дополнение к поиску максимума просят определить, есть ли в строке числа, делящиеся на определенное значение (например, 17). Разберем, как это сделать без перебора.

Существует математический трюк: произведение остатков. Если хотя бы одно число в наборе делится на 17, то произведение остатков от деления каждого числа на 17 будет равно 0.

Однако в 1С мы столкнемся с переполнением при перемножении. Поэтому можно применить метод «Псевдо-лямбды», используя Вычислить() и вспомогательную функцию:


Функция ПроверитьДелимость(Контекст)
    Элемент = Число(Контекст.Коллекция[Контекст.Индекс]);
    Контекст.Индекс = Контекст.Индекс + 1;
    Если Элемент % 17 = 0 Тогда
        Контекст.Найдено = Истина;
    КонецЕсли;
    Возврат "";
КонецФункции

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

Способ 5: Механизм запросов (самый надежный)

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

  1. Разделяем строку на массив строк-чисел.
  2. Передаем массив в запрос как параметр.
  3. В запросе используем ВЫБРАТЬ МАКСИМУМ(...).

Важно: Чтобы запрос корректно сравнил числа, а не строки, внутри запроса нужно использовать конструкцию ВЫРАЗИТЬ(Поле КАК ЧИСЛО), если данные передаются через временную таблицу с типизацией.

Рекомендации для работы

При выборе метода всегда учитывайте следующее:

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

← На главную