Часто перед программистами 1С встает задача автоматического подбора документов из списка таким образом, чтобы их сумма максимально приближалась к заданному значению. На первый взгляд, это кажется классической задачей о рюкзаке или задачей о сумме подмножеств, однако при попытке реализации стандартных алгоритмов динамического программирования на языке 1С мы сталкиваемся с критическими проблемами: нехваткой оперативной памяти и низкой скоростью обработки больших массивов данных.
Давайте проанализируем, почему стандартные подходы не работают и как можно выйти из этой ситуации с минимальными затратами ресурсов.
Классический алгоритм, который использует создание матрицы (двумерного массива), требует выделения памяти пропорционально произведению количества элементов на целевую сумму. Если ваша цель — 10 000 рублей, а документов 100, массив будет содержать 1 000 000 ячеек. При увеличении суммы до 1 000 000 ячеек количество операций становится критичным для интерпретатора 1С, что приводит к зависанию или ошибке переполнения памяти.
Кроме того, если суммы документов имеют дробную часть (копейки), их необходимо приводить к целым числам (умножать на 100), что еще сильнее раздувает размерность матрицы. Мы должны осознать: 1С не предназначена для интенсивных математических вычислений в циклах с большой глубиной вложенности.
Рассмотрим несколько эффективных стратегий, которые позволят решить задачу подбора суммы, не «убивая» производительность системы.
Этот метод не всегда дает математически идеальный результат, но он работает мгновенно и в большинстве бизнес-задач этого более чем достаточно.
Если количество документов невелико (например, до 40-50 штук), можно использовать этот алгоритм:
Если суммы слишком велики, попробуйте их нормализовать. Например, вычислите наибольший общий делитель (НОД) для всех сумм. Если суммы кратны какому-то числу, разделите их на него. Это значительно уменьшит размерность данных, с которыми будет работать алгоритм.
Хотя рекурсия может привести к переполнению стека при больших объемах, для небольшого количества элементов она позволяет быстро описать логику перебора:
Функция ПолучитьСуммуРекурсивно(_Массив, _Индекс, _Сумма)
_См = _Массив[_Индекс].Значение;
Если _См = _Сумма Тогда
Возврат _См;
КонецЕсли;
Для иии = _Индекс + 1 по _Массив.РазмерМассива Цикл
_тСм = _Массив[_Индекс + 1].Значение;
Если _тСм <= _Сумма - _См Тогда
_См = _См + ПолучитьСуммуРекурсивно(_Массив, иии, _Сумма);
КонецЕсли;
КонецЦикла;
Возврат _См;
КонецФункции
При разработке алгоритмов подбора в 1С следуйте этим принципам:
Массив в оперативной памяти. Если данных много, лучше выгружать их во временные таблицы (ТЗ) или использовать индексы для быстрого поиска.В завершение, помните: если задача требует сложной оптимизации, не бойтесь вынести расчет в отдельный сервис или внешнюю обработку, работающую на более производительных языках, но для 99% бизнес-задач комбинация «жадного» поиска с последующей локальной корректировкой является идеальным решением.