В процессе автоматизации часто возникает задача «нарезки» общего количества изделий на партии (пакеты) с фиксированным лимитом. Например, при формировании коробов, страниц этикеток или транспортных упаковок, где общее количество позиции в пакете не должно превышать определенное значение ОграничениеКоличестваПакета. Если позиция превышает этот лимит, «хвост» должен быть перенесен в следующий пакет.
Рассмотрим, как реализовать этот алгоритм на встроенном языке 1С, проанализировав несколько подходов.
Основная идея заключается в использовании цикла Для Каждого по строкам исходной таблицы и вложенного цикла Пока, который «откусывает» от исходного количества порции, равные заданному размеру пакета. Для реализации нам потребуется создать новую ТаблицаЗначений, в которую мы будем добавлять строки с указанием номера пакета.
Рассмотрим вариант реализации, который корректно учитывает остатки и заполняет таблицу результатов:
Функция РаспределениеПоПакетам(Знач ИсходнаяТаблица, ОграничениеКоличестваПакета)
ТаблицаРезультат = ИсходнаяТаблица.СкопироватьКолонки();
ТаблицаРезультат.Колонки.Добавить("НомерПакета", Новый ОписаниеТипов("Число"));
НомерТекущегоПакета = 1;
КоличествоТекущегоПакета = 0;
Для Каждого ИсходнаяСтрока Из ИсходнаяТаблица Цикл
КоличествоОстаток = ИсходнаяСтрока.Количество;
Пока КоличествоОстаток > 0 Цикл
СтрокаРезультат = ТаблицаРезультат.Добавить();
ЗаполнитьЗначенияСвойств(СтрокаРезультат, ИсходнаяСтрока);
ДопустимыйОстатокВПакете = ОграничениеКоличестваПакета - КоличествоТекущегоПакета;
КоличествоКРаспределению = Мин(КоличествоОстаток, ДопустимыйОстатокВПакете);
СтрокаРезультат.Количество = КоличествоКРаспределению;
СтрокаРезультат.НомерПакета = НомерТекущегоПакета;
КоличествоОстаток = КоличествоОстаток - КоличествоКРаспределению;
КоличествоТекущегоПакета = КоличествоТекущегоПакета + КоличествоКРаспределению;
Если КоличествоТекущегоПакета >= ОграничениеКоличестваПакета Тогда
НомерТекущегоПакета = НомерТекущегоПакета + 1;
КоличествоТекущегоПакета = 0;
КонецЕсли;
КонецЦикла;
КонецЦикла;
Возврат ТаблицаРезультат;
КонецФункции
Часто программисты стремятся к лаконичности кода. Важно понимать, что при экстремальном сокращении кода (до 10-12 строк) страдает читаемость и устойчивость алгоритма к ошибкам. Однако, использование встроенных методов, таких как Мин(), позволяет значительно упростить логику сравнения остатков.
Разберем ключевые моменты, которые необходимо соблюдать:
ИсходнаяТаблица.Скопировать().НомерПакета обязательно используйте ОписаниеТипов, чтобы избежать проблем с приведением типов при расчетах.Пока должно всегда опираться на изменение исходного значения, иначе алгоритм уйдет в «бесконечный цикл» при Количество > 0.Если ваша ТаблицаЗначений содержит тысячи строк, перебор через Для Каждого и динамическое добавление строк может потребовать значительных ресурсов памяти. В высоконагруженных системах лучше применять следующие практики:
ТаблицаЗначений во временную таблицу базы данных и обработать её с помощью Запрос, используя возможности SQL-сервера.КоличествоВПакете. Если он равен 0 или является отрицательным числом, это приведет к ошибке деления или бесконечному циклу. Добавьте проверку Если ОграничениеКоличестваПакета <= 0 Тогда Возврат Неопределено; КонецЕсли; в самом начале функции.Подводя итог, можно сказать, что данная задача является классической проверкой навыков алгоритмического мышления в 1С. Главное — это соблюдение баланса между лаконичностью кода и его понятностью для других разработчиков, которые будут поддерживать этот код в будущем.