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

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

В процессе разработки на платформе 1С часто возникает задача оптимизации данных, хранящихся в ТаблицаЗначений. Одной из типичных ситуаций является необходимость «схлопывания» строк: если значение в строке меньше заданного порога, мы хотим перенести это значение в другую строку, а саму исходную запись удалить, чтобы итоговая сумма по колонке осталась неизменной.

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

Почему нельзя просто удалять строки в цикле «Для Каждого»?

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

Способ 1: Обход таблицы значений с конца

Самый простой способ избежать проблем со смещением индексов — это обход таблицы в обратном порядке: от последнего элемента к первому. При таком подходе удаление строки с индексом N никак не влияет на индексы строк от 0 до N-1, которые нам еще предстоит обработать.

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


Индекс = ТаблицаЗначений.Количество() - 1; 
Пока Индекс >= 0 Цикл  
    Если ТаблицаЗначений[Индекс].Число < 5 Тогда 
        // Переносим значение в предыдущую строку
        ТаблицаЗначений[Индекс - 1].Число = ТаблицаЗначений[Индекс - 1].Число + ТаблицаЗначений[Индекс].Число;
        ТаблицаЗначений.Удалить(Индекс);
    Иначе
        Индекс = Индекс - 1;
    КонецЕсли; 
КонецЦикла;

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

Способ 2: Использование массива для отложенного удаления

Этот метод считается более современным и понятным. Мы разделяем логику поиска строк и логику изменения данных. Сначала мы проходим по таблице, аккумулируем «лишние» значения в переменной, а строки, которые нужно удалить, собираем в отдельный Массив. Это позволяет избежать любых конфликтов с индексацией.

Разберем алгоритм по шагам:

  1. Инициализируем переменную ОсталосьЧасовНаПроект для накопления суммы удаляемых значений.
  2. Создаем Массив для хранения ссылок на строки, подлежащие удалению.
  3. Обходим таблицу и при выполнении условия прибавляем значение к аккумулятору, добавляя строку в массив.
  4. Если строка проходит по условию, прибавляем к ней накопленное значение (если оно есть) и обнуляем аккумулятор.
  5. После цикла выполняем удаление строк из массива через метод ТЗ.Удалить().

ОсталосьЧасовНаПроект = 0;
МассивСтрокДляУдаления = Новый Массив;

Для Каждого Стр Из ТЗ Цикл 
    Если Стр.ЧасовНаПроект < 8 Тогда
        ОсталосьЧасовНаПроект = ОсталосьЧасовНаПроект + Стр.ЧасовНаПроект;
        МассивСтрокДляУдаления.Добавить(Стр);
    ИначеЕсли ОсталосьЧасовНаПроект > 0 Тогда
        Стр.ЧасовНаПроект = Стр.ЧасовНаПроект + ОсталосьЧасовНаПроект;
        ОсталосьЧасовНаПроект = 0;
    КонецЕсли;
КонецЦикла;

Для Каждого СтрУдалить Из МассивСтрокДляУдаления Цикл
    ТЗ.Удалить(СтрУдалить);    
КонецЦикла;

// Проверяем остаток после завершения цикла
Если ОсталосьЧасовНаПроект > 0 И ТЗ.Количество() > 0 Тогда
    ТЗ[0].ЧасовНаПроект = ТЗ[0].ЧасовНаПроект + ОсталосьЧасовНаПроект;
КонецЕсли;

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

Если ваша задача сводится к простому суммированию показателей по определенному ключу (например, по сотруднику или проекту), всегда анализируйте, нельзя ли применить метод ТаблицаЗначений.Свернуть(). Это штатный механизм 1С, который работает значительно быстрее любого ручного перебора циклом. Он автоматически суммирует числа и удаляет дублирующие строки, группируя данные по заданным колонкам.

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

← На главную