Как распределить номенклатуру из таблицы значений на пакеты заданного размера?

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

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

Рассмотрим, как реализовать этот алгоритм на встроенном языке 1С, проанализировав несколько подходов.

Базовый алгоритм распределения

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

Рассмотрим вариант реализации, который корректно учитывает остатки и заполняет таблицу результатов:


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

Оптимизированный подход к коду

Часто программисты стремятся к лаконичности кода. Важно понимать, что при экстремальном сокращении кода (до 10-12 строк) страдает читаемость и устойчивость алгоритма к ошибкам. Однако, использование встроенных методов, таких как Мин(), позволяет значительно упростить логику сравнения остатков.

Разберем ключевые моменты, которые необходимо соблюдать:

  1. Сохранность данных: Всегда работайте с копией исходной таблицы. Если вы изменяете исходный объект в цикле, это приведет к ошибкам в других частях программы, где эти данные еще могут потребоваться. Используйте ИсходнаяТаблица.Скопировать().
  2. Типизация: При добавлении колонки НомерПакета обязательно используйте ОписаниеТипов, чтобы избежать проблем с приведением типов при расчетах.
  3. Контроль зацикливания: Условие в цикле Пока должно всегда опираться на изменение исходного значения, иначе алгоритм уйдет в «бесконечный цикл» при Количество > 0.

Рекомендации по производительности

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

Подводя итог, можно сказать, что данная задача является классической проверкой навыков алгоритмического мышления в 1С. Главное — это соблюдение баланса между лаконичностью кода и его понятностью для других разработчиков, которые будут поддерживать этот код в будущем.

← На главную